Documentation

Sign in with Davi

Add a sign-in button with OpenID Connect, and read the user's identity from the id_token.

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:

HostDoes
davi.socialSigns the user in and shows the consent screen
api.davi.socialIssues 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:

  1. Verify the signature against the JWKS at https://api.davi.social/oauth2/.well-known/jwks.json. Cache the keys and select by the token's kid.
  2. Check iss equals the issuer in the discovery document, exactly. A trailing slash is a mismatch.
  3. Check aud is your client_id.
  4. Check exp has not passed.
  5. Check nonce matches 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:

ScopeAdds
openidsub, the stable user identifier
profileName, username, avatar
emailemail, 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.