This page adds a "Sign in with Davi" button: it signs a user in and tells you
who they are in one round trip. It is the
authorization code flow with the openid scope
added, so the token response also carries an id_token describing the user.
The flow spans two hosts:
| Host | Does |
|---|---|
davi.social | Signs the user in and shows the consent screen |
api.davi.social | Issues and validates tokens |
Send the user's browser to davi.social. The API host answers in JSON for your
server.
1. Ask for openid
GET https://davi.social/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/callback
&scope=openid profile email
&state=RANDOM_STATE
&nonce=RANDOM_NONCE
&code_challenge=CODE_CHALLENGE
&code_challenge_method=S256
Without openid you get an access token and no id_token. Add profile for
name and avatar, and email for the address.
nonce is echoed into the id_token, which proves the token answers this
request and was not replayed from an earlier one. Generate a new nonce per
attempt alongside state, and keep both.
2. Handle the redirect
Davi signs the user in if needed, then shows a consent screen naming your application and the scopes you asked for. If they approved these scopes before, the screen is skipped and they are redirected back immediately.
If they decline, they return to your redirect_uri with
?error=access_denied&state=.... Treat it as a normal outcome, not an error.
You may be granted fewer scopes than you asked for. A user can only consent to what they can actually do, so a request naming scopes beyond their reach is narrowed rather than refused. Read the granted set from the token response.
3. Exchange the code
Exchange it exactly as in
Sign-in, against the
API host. With openid in the granted scopes, the response carries an
id_token:
{
"access_token": "…",
"refresh_token": "…",
"id_token": "eyJhbGciOiJSUzI1NiIs…",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid profile email"
}
4. Validate the id_token
The id_token is a signed JWT. Validate it before trusting it:
- Verify the signature against the JWKS at
https://api.davi.social/oauth2/.well-known/jwks.json. Cache the keys and select by the token'skid. - Check
issequals theissuerin the discovery document, exactly. A trailing slash is a mismatch. - Check
audis yourclient_id. - Check
exphas not passed. - Check
noncematches the one you sent in step 1.
Use a JWT library for your language rather than verifying by hand.
The discovery document lists every endpoint and the algorithms in use. Read the endpoints from it rather than hard-coding them:
curl "https://api.davi.social/oauth2/.well-known/openid-configuration"
5. Read the claims
The id_token carries the user's identity, so no further call is needed:
| Scope | Adds |
|---|---|
openid | sub, the stable user identifier |
profile | Name, username, avatar |
email | email, and whether it is verified |
Store sub as the user's identifier. It is stable for that user, while a
username or email address can change and be reused. Treat the other claims as
display data that may differ at the next sign-in.
The id_token is a snapshot from the moment the user approved. For current
claims later, call GET /oauth2/userinfo with the access token.
Next
- Sign-in: the underlying flow, refresh and sign-out.
- Scopes: everything else you can ask for.
- Fetching a User: the API's fuller user record.