OAuth and OpenID Connect endpoints
Look up every endpoint an application calls to sign people in, with its parameters, responses, scopes and errors.
Every endpoint on this page is on your project's issuer, the project's URL. The examples use https://acme.authfi.io. An OpenID Connect library reads all of them from the OpenID configuration.
An AI agent signs in at a separate token endpoint. See Give an AI agent an identity.
Authorize
Starts the authorization code flow: the browser goes here, the person signs in, and the browser returns to your application with a code.
GET
/oauth/authorizeAuthentication. None. The browser makes this request, and the application is identified by client_id.
Parameters. Sent in the query string.
Example request.
https://acme.authfi.io/oauth/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=https%3A%2F%2Fapp.acme.com%2Fcallback&scope=openid%20profile%20email&state=$STATE&code_challenge=$CHALLENGE&code_challenge_method=S256$CLIENT_ID is shown in the console when you register the application. $STATE and $CHALLENGE are values your application creates. See Add sign-in to an app.
Example response. The browser returns to redirect_uri.
https://app.acme.com/callback?code=Xq3v...&state=5f2a...&iss=https%3A%2F%2Facme.authfi.ioResponse fields.
Errors. Where the error appears depends on what is wrong.
The browser is never sent to a URI that is not registered.
Every code is listed under Errors.
Token
Issues tokens. One endpoint serves three grants, chosen by grant_type.
POST
/oauth/tokenAuthentication. An application with a client secret authenticates with HTTP Basic, or with client_id and client_secret in the body. An application without a secret sends client_id only.
Parameters. Sent form-encoded in the body. Every request carries grant_type, and each grant adds its own parameters.
Authorization code grant
Exchanges the code from Authorize for tokens. See Add sign-in to an app.
curl https://acme.authfi.io/oauth/token \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri=https://app.acme.com/callback \
-d client_id="$CLIENT_ID" \
-d code_verifier="$VERIFIER"$CODE is the code from the redirect. $VERIFIER is the PKCE verifier whose challenge you sent to Authorize.
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6Ii4uLiJ9...",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "...",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ii4uLiJ9...",
"scope": "openid profile email"
}Refresh token grant
Exchanges a refresh token for new tokens. Each refresh token works once, and every use returns a new one. See Refresh tokens.
curl https://acme.authfi.io/oauth/token \
-d grant_type=refresh_token \
-d refresh_token="$REFRESH_TOKEN" \
-d client_id="$CLIENT_ID"The response has the same shape as for the authorization code grant. sid, amr and auth_time in the new tokens are those of the original sign-in.
Client credentials grant
Issues an access token to a backend service, for one API. Only a machine-to-machine (m2m) application may use it. See Service to service.
curl https://acme.authfi.io/oauth/token \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d grant_type=client_credentials \
-d resource="$API_CLIENT_ID"$API_CLIENT_ID is the client ID of the API's application. The calling application must hold a grant on it.
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6Ii4uLiJ9...",
"token_type": "Bearer",
"expires_in": 900
}Token response
Response fields. The response carries Cache-Control: no-store.
The client credentials grant returns an access token only.
Errors.
Userinfo
Returns the profile of the person an access token was issued for.
GET
/oauth/userinfoAuthentication. The access token, as Authorization: Bearer.
Parameters. None. POST is accepted too.
Example request.
curl https://acme.authfi.io/oauth/userinfo \
-H "Authorization: Bearer $ACCESS_TOKEN"Example response.
{
"sub": "[email protected]",
"email": "[email protected]",
"email_verified": true,
"name": "Ada Lovelace",
"groups": ["engineering"],
"roles": ["developer"]
}Response fields. The fields returned depend on the scopes of the access token.
The profile is read on each call, so a changed name shows at once. groups and roles are those in the access token.
Errors. None specific to this endpoint. See Errors.
Check a token
Tells an application whether an access token is active (token introspection).
POST
/oauth/token/introspectAuthentication. The client ID and client secret of an application that has a secret. The example sends them as HTTP Basic.
Parameters. Sent form-encoded in the body.
Example request.
curl https://acme.authfi.io/oauth/token/introspect \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-d token="$ACCESS_TOKEN"Example response.
{
"active": true,
"scope": "openid profile email",
"client_id": "3f9c2b7e...",
"sub": "[email protected]",
"iss": "https://acme.authfi.io",
"exp": 1760000900,
"iat": 1760000000,
"token_type": "Bearer"
}Response fields.
Errors. A token that is expired, malformed or not an access token returns {"active": false} and no other field.
An access token is a signed JWT, so a service can also validate it without a call. See Checking a token.
Revoke a token
Revokes a refresh token, and with it every refresh token descended from the same sign-in.
POST
/oauth/token/revokeAuthentication. The application's client_id, in the body.
Parameters. Sent form-encoded in the body.
Example request.
curl https://acme.authfi.io/oauth/token/revoke \
-d token="$REFRESH_TOKEN" \
-d client_id="$CLIENT_ID"Example response. 200 with an empty body, whether or not the token existed.
Errors. None specific to this endpoint. See Errors.
This endpoint acts on refresh tokens. An access token stays valid until it expires, which is why access tokens last 15 minutes by default. To end a person's access sooner, end their session or remove their access. See Sign out.
Sign out
Ends the person's session and removes its cookie. This is the end-session endpoint.
GET
/oauth/logoutAuthentication. None. The browser makes this request.
Parameters. Sent in the query string.
Example request.
https://acme.authfi.io/oauth/logout?client_id=$CLIENT_ID&post_logout_redirect_uri=https%3A%2F%2Fapp.acme.com%2F&state=abcResponse. The outcome depends on the parameters.
Errors. None specific to this endpoint.
To also stop the refresh token your application holds, revoke it. See Sign out.
Keys
Returns the project's public signing keys as a JWK Set (RFC 7517).
GET
/.well-known/jwks.jsonAuthentication. None.
Parameters. None.
Example request.
curl https://acme.authfi.io/.well-known/jwks.jsonResponse. The set holds one RS256 key and one EdDSA (Ed25519) key.
Each token names its key in the kid header. Keys rotate, and a rotated key stays published for 24 hours. Fetch the set when you meet a kid you do not know, not on every request, and do not pin one key. See Keys and secrets.
Errors. None specific to this endpoint.
Scopes
A scope is a name your application sends in scope to say what it wants. Send several separated by spaces.
Userinfo returns sub with any scope. profile and email decide what else userinfo returns. The ID token carries email, email_verified, name, groups and roles whatever scopes you request. See ID token.
Errors
Every endpoint on this page reports a failure as OAuth 2.0 defines (RFC 6749): a code in error, and sometimes a sentence in error_description.
{ "error": "invalid_grant", "error_description": "authorization code is invalid or expired" }The authorization endpoint sends the same two fields, with state, as query parameters on the redirect URI.
For what to do about each code, see Errors.