Authorization Code & Implicit
Implement user login with the authorization code flow, refresh tokens, and the implicit grant.
Authorization Code
The authorization code flow is a two-step redirect: the user is sent to the auth server, authenticates, then comes back to your app with a code that you exchange for tokens.
Endpoints
| Authorization | User redirects to https://auth.xeonr.io/auth/authorize |
| Token exchange | POST https://auth.xeonr.io/api/v1/oauth/token |
| Token revocation | POST https://auth.xeonr.io/api/v1/oauth/revoke |
| UserInfo | GET https://auth.xeonr.io/api/v1/userinfo |
| JWKS | GET https://auth.xeonr.io/.well-known/jwks.json |
Step 1 — Redirect the user to the authorization endpoint
Build a URL to https://auth.xeonr.io/auth/authorize and redirect the user's browser to it.
Required parameters:
| Parameter | Value |
|---|---|
response_type | code |
client_id | Your client UUID |
redirect_uri | Must exactly match your registered redirect URI |
scope | Space-separated scopes (must include openid for ID tokens) |
state | A random opaque string — verify this on return to prevent CSRF |
Optional parameters:
| Parameter | Description |
|---|---|
code_challenge | Base64url-encoded PKCE challenge (recommended for public clients) |
code_challenge_method | S256 (recommended) or plain |
nonce | Required if response_type includes id_token |
max_age | Maximum authentication age in seconds |
https://auth.xeonr.io/auth/authorize
?response_type=code
&client_id=550e8400-e29b-41d4-a716-446655440000
&redirect_uri=https%3A%2F%2Fmyapp.example.com%2Fcallback
&scope=openid%20profile%20email
&state=abc123
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256Step 2 — Handle the redirect back
After the user authenticates, they are redirected to your redirect_uri with:
| Parameter | Description |
|---|---|
code | Short-lived authorization code — exchange this immediately |
state | The state value you sent — verify it matches |
https://myapp.example.com/callback?code=AUTH_CODE&state=abc123Reject the response if state doesn't match what you sent.
Step 3 — Exchange the code for tokens
POST /api/v1/oauth/token HTTP/1.1
Host: auth.xeonr.io
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTH_CODE
&client_id=550e8400-e29b-41d4-a716-446655440000
&client_secret=YOUR_CLIENT_SECRET
&redirect_uri=https%3A%2F%2Fmyapp.example.com%2Fcallback
&code_verifier=YOUR_CODE_VERIFIERAlternatively, pass client_id and client_secret as HTTP Basic auth:
Authorization: Basic base64(client_id:client_secret)Parameters:
| Parameter | Required | Description |
|---|---|---|
grant_type | Yes | authorization_code |
code | Yes | Authorization code from the redirect |
client_id | Yes | Your client UUID |
client_secret | Confidential clients | Your client secret |
redirect_uri | Yes | Must match the original request exactly |
code_verifier | If PKCE was used | 43–128 character base64url-encoded verifier |
Response:
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJ...",
"id_token": "eyJ...",
"scope": "openid profile email"
}refresh_token is only present if you requested the offline_access scope.
id_token is only present if you requested the openid scope.
Using the access token
Include the access token as a Bearer token on API requests:
Authorization: Bearer eyJ...Fetching user data
Use the UserInfo endpoint to retrieve claims about the authenticated user. The token must include the openid scope.
GET /api/v1/userinfo HTTP/1.1
Host: auth.xeonr.io
Authorization: Bearer eyJ...The response varies based on which scopes were granted:
{
"sub": "urn:xeonr:user:12345",
"email": "[email protected]",
"email_verified": true,
"nickname": "username",
"preferred_username": "username",
"picture": "https://cdn.upl.im/...",
"groups": ["admin", "editor"]
}| Field | Scope required | Description |
|---|---|---|
sub | openid | Always present. Stable user URN |
email | email | User's email address |
email_verified | email | Always true for verified accounts |
nickname | profile | Username |
preferred_username | profile | Username |
picture | profile | Avatar URL, omitted if no avatar is set |
groups | groups | Array of role names within the application |
To verify tokens independently, fetch the JWKS and validate the JWT signature:
GET https://auth.xeonr.io/.well-known/jwks.jsonRefreshing tokens
If you requested offline_access, you received a refresh_token. Use it to get a new access token without user interaction.
POST /api/v1/oauth/token HTTP/1.1
Host: auth.xeonr.io
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=eyJ...
&client_id=550e8400-e29b-41d4-a716-446655440000
&client_secret=YOUR_CLIENT_SECRETResponse:
{
"access_token": "eyJ...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJ...",
"scope": "openid profile email"
}The returned refresh_token replaces the previous one. Store it and discard the old value.
Requirements:
offline_accessmust have been in the original scope requestsupports_refresh_tokenmust be enabled on your client
Revoking tokens
To log a user out or invalidate a token:
POST /api/v1/oauth/revoke HTTP/1.1
Host: auth.xeonr.io
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
token=eyJ...
&token_type_hint=refresh_tokentoken_type_hint is optional — either access_token or refresh_token.
Implicit grant
The implicit grant returns an access token directly in the URL fragment, skipping the code exchange. There are no refresh tokens.
This flow is only available on clients with supports_implicit_grant enabled. For new integrations, use Authorization Code with PKCE instead.
Redirect the user
https://auth.xeonr.io/auth/authorize
?response_type=token
&client_id=550e8400-e29b-41d4-a716-446655440000
&redirect_uri=https%3A%2F%2Fmyapp.example.com%2Fcallback
&scope=openid%20profile
&state=abc123Handle the fragment response
The user is redirected to your redirect_uri with the token in the URL fragment (not the query string — it's not sent to your server):
https://myapp.example.com/callback
#access_token=eyJ...
&token_type=Bearer
&expires_in=3600
&state=abc123Parse the fragment in the browser and verify state. The offline_access scope cannot be used with the implicit grant.