This page signs in a Davi user and gets an access token that acts on their behalf. You need a registered app's Client ID, and its secret if the app is confidential. The flow uses PKCE, so it works for confidential and public clients alike.
1. Create a PKCE pair
Generate a random code_verifier and derive its S256 code_challenge
(code_challenge = BASE64URL(SHA256(code_verifier))):
function base64url(bytes) {
return btoa(String.fromCharCode(...new Uint8Array(bytes)))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
}
const codeVerifier = base64url(crypto.getRandomValues(new Uint8Array(32)));
const codeChallenge = base64url(
await crypto.subtle.digest("SHA-256", new TextEncoder().encode(codeVerifier)),
);
Keep the code_verifier for step 3. Send only the code_challenge in step 2.
2. Send the user to /authorize
Direct the user's browser to davi.social. It handles sign-in and consent, then
redirects back to your redirect_uri.
GET https://davi.social/oauth/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://yourapp.com/callback
&scope=openid profile
&state=RANDOM_STATE
&code_challenge=CODE_CHALLENGE
&code_challenge_method=S256
Send an unguessable state and verify it on return, to protect against CSRF.
On success Davi redirects to:
https://yourapp.com/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE
If the user declines, you receive ?error=access_denied&state=... instead.
Send the browser to
davi.social, notapi.davi.social. The API host answers this endpoint in JSON:401 { "error": "login_required" }with no session, or200 { "consent_required": true, ... }when consent is still needed. A person cannot complete the flow there.
3. Exchange the code for tokens
Exchange the code at the token endpoint. Confidential clients authenticate with
their secret. Public clients rely on the code_verifier.
curl -X POST "https://api.davi.social/oauth2/token" \
-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://yourapp.com/callback" \
-d "code_verifier=CODE_VERIFIER"
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "def502...",
"scope": "openid profile",
"id_token": "eyJhbGciOi..."
}
Authorization codes are single-use and expire after 10 minutes.
4. Refresh the access token
Access tokens last one hour. Use the refresh token to get a new one:
curl -X POST "https://api.davi.social/oauth2/token" \
-u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=REFRESH_TOKEN"
You may request a narrower scope on refresh, never a wider one.
Refresh tokens rotate on every use, and replaying a spent one revokes the session. Persist the new
refresh_tokenfrom each response before using it, and run only one refresh at a time. Two concurrent refreshes, or a retry that re-sends an already-used token, log the user out. The symptom is intermittent logouts.
Signing out
Revoke a token with POST /oauth2/revoke. Users can also revoke your app's
access from their Davi settings, which invalidates its tokens.
Next
- Scopes: choose the permissions to request.
- Making Requests: call the API with your token.