Add Sign in with Ppoppo (OAuth2 PKCE)
This guide wires Sign in with Ppoppo end to end. It assumes you have registered a login client (see the Quickstart). For exact endpoint parameters and token fields, follow the links into the Sign-in reference — this page is the recipe, not the field tables.
Every Ppoppo login client uses PKCE S256.
1. Generate a PKCE pair
Before redirecting the user, generate a fresh code_verifier (43–128 characters) and derive its code_challenge (base64url-encoded SHA-256). Generate a new pair for every login attempt.
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return base64UrlEncode(array);
}
async function generateCodeChallenge(verifier) {
const data = new TextEncoder().encode(verifier);
const digest = await crypto.subtle.digest('SHA-256', data);
return base64UrlEncode(new Uint8Array(digest));
}
function base64UrlEncode(buffer) {
return btoa(String.fromCharCode(...buffer))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
const codeVerifier = generateCodeVerifier();
const codeChallenge = await generateCodeChallenge(codeVerifier);import secrets, hashlib, base64
def _b64url(data: bytes) -> str:
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("ascii")
def generate_code_verifier() -> str:
return _b64url(secrets.token_bytes(32))
def generate_code_challenge(verifier: str) -> str:
return _b64url(hashlib.sha256(verifier.encode("ascii")).digest())Keep the code_verifier for the token exchange (e.g. in the user's session).
2. Redirect to the authorization endpoint
Send the user to GET /oauth/authorize with your client_id, redirect_uri, response_type=code, scope, a random state, the code_challenge, and code_challenge_method=S256:
https://accounts.ppoppo.com/oauth/authorize
?client_id=yourapp_login_client
&redirect_uri=https://yourapp.com/auth/callback
&response_type=code
&scope=openid%20profile
&state=RANDOM_STATE
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256Request only the scopes you need — add email to receive the user's address, messaging / poll to use the External API. The full parameter table is in the authorization endpoint reference.
3. Handle the callback
Ppoppo redirects back to your redirect_uri with code and state. Verify state matches the value you sent, then proceed. If the callback carries error instead, surface error_description — see Errors.
4. Exchange the code for tokens
From your server (never the browser), POST /oauth/token:
grant_type=authorization_code
&code=AUTH_CODE
&redirect_uri=https://yourapp.com/auth/callback
&client_id=yourapp_login_client
&code_verifier=ORIGINAL_CODE_VERIFIERThe code_verifier authenticates the client — there is no client_secret. You receive an access_token (1 hour), a refresh_token (180-day inactivity), and an id_token when openid was requested. See the token fields.
5. Fetch the user
Call GET /oauth/userinfo with the access token to get the user's sub (ppnum_id) and ppnum. Find-or-create a record keyed by sub, and store the encrypted refresh token against the session — see the User mapping guide.
6. Refresh before expiry
The access token lasts one hour. Refresh with grant_type=refresh_token; the same refresh token stays valid (no rotation). If a refresh fails with invalid_grant, the user has revoked access — clear stored tokens and send them back through step 2.
Incomplete accounts
If a user has not finished Ppoppo registration, the callback returns error=account_setup_required. Prompt them to complete their Ppoppo registration, then retry.
Keep tokens on the server, out of reach of browser JavaScript (HttpOnly cookies or a server-side session). Encrypt refresh tokens at rest. More in Security.