Sign in with GitCafe
GitCafe is an OpenID Connect provider. Your service can add a Sign in with GitCafe button that tells you who the person is, and, in the same approval, ask for access to their repositories. Any standard OpenID Connect client library works; this guide shows the settings it needs.
What you get
| You ask for | The person approves | You receive |
|---|---|---|
openid (with profile, email as you need) | Who they are, nothing else | An ID token, and an access token that reads only userinfo |
openid plus repository permissions | Who they are and the repositories they pick | An ID token, and an access token for the API, MCP or Git |
| Repository permissions alone | The repositories they pick | An access token, as for MCP apps |
A sign-in alone never shows a repository picker: the consent screen lists only what you learn about the person, and says you cannot read their repositories.
Discovery
Point your library at the issuer https://git.cafe. It reads
https://git.cafe/.well-known/openid-configuration, which names:
| Field | Value |
|---|---|
authorization_endpoint | https://git.cafe/api/oauth/authorize |
token_endpoint | https://git.cafe/api/oauth/token |
userinfo_endpoint | https://git.cafe/api/oauth/userinfo |
jwks_uri | https://git.cafe/api/oauth/jwks |
registration_endpoint | https://git.cafe/api/oauth/register |
| ID token signature | RS256 |
| Client authentication | none: public clients with PKCE (S256) |
Register your client
Clients are public: there is no client secret, and every authorization uses
PKCE with S256. Register once and keep the client_id:
| 1 | curl -X POST https://git.cafe/api/oauth/register \ |
| 2 | -H 'content-type: application/json' \ |
| 3 | -d '{"client_name":"Tripwire","redirect_uris":["https://tripwire.sh/auth/callback/gitcafe"]}' |
The redirect URI must match exactly on every request. A registered app can instead use the client its publisher registers in the app's settings, which names the app and its publisher on the consent screen; an unregistered client is shown as unverified.
Scopes
| Scope | Claims in the ID token and userinfo |
|---|---|
openid | sub: the person's GitCafe account ID, which never changes |
profile | preferred_username, name, picture, profile |
email | email, email_verified |
Use sub as the account key. Usernames can change; the ID cannot, and is never
given to anyone else.
To ask for repository access in the same approval, add permission scopes
(repo:contents:read, issue:contents:write and the others in
scopes_supported) and a resource naming where the token is used:
https://git.cafe/api, https://git.cafe/mcp or, for an app, https://git.cafe/git.
A sign-in alone needs no resource.
Tokens
The token response carries id_token whenever the approval included
openid. The ID token is valid for 10 minutes and carries iss, aud (your
client ID), exp, iat, your nonce and at_hash; verify it against the
JWKS. Access tokens last at most 15 minutes. A refresh returns a new ID token
for the same person, without a nonce.
GET or POST to userinfo with Authorization: Bearer <access token>
returns the claims the person approved. Any live access token from the
connection works there; a sign-in's token works nowhere else.
The connection lasts until the person removes it in Authorized apps or leaves it unused for 90 days.
Library settings
Auth.js (NextAuth):
| 1 | { |
| 2 | id: "gitcafe", |
| 3 | name: "GitCafe", |
| 4 | type: "oidc", |
| 5 | issuer: "https://git.cafe", |
| 6 | clientId: process.env.GITCAFE_CLIENT_ID, |
| 7 | client: { token_endpoint_auth_method: "none" }, |
| 8 | checks: ["pkce", "state", "nonce"], |
| 9 | authorization: { params: { scope: "openid profile email" } }, |
| 10 | } |
openid-client (Node):
| 1 | const config = await client.discovery( |
| 2 | new URL("https://git.cafe"), |
| 3 | process.env.GITCAFE_CLIENT_ID, |
| 4 | undefined, |
| 5 | client.None(), |
| 6 | ); |
Other libraries need the same four things: the issuer, the client ID, no
client secret (token_endpoint_auth_method none) and PKCE.
Brand
Label the button Sign in with GitCafe, with the GitCafe name and its square mark. In monochrome the mark is a plain filled square.