Get started
Quickstart
Sign a person in with the authorization code flow and PKCE, step by step.
This walkthrough signs a person in to a server-side web app with the authorization code flow and PKCE. It uses example-app as the client ID and https://app.example.com/callback as the redirect URI; use your own registered values.
Before you start
- A registered application with a
client_idand at least one redirect URI. See Request access. - For a server-side app, its client secret, kept in your secret manager. Browser and mobile apps are registered as public clients and have no secret.
- An OpenID Connect library, configured with the issuer
https://sso.aldelo.com.
1. Discover the endpoints
Fetch the discovery document once at startup and cache it. It lists every endpoint and capability:
GET https://sso.aldelo.com/.well-known/openid-configuration
{
"acr_values_supported": [
"urn:aldelo:sso:acr:pwd",
"urn:aldelo:sso:acr:mfa",
"urn:aldelo:sso:acr:phone"
],
"authorization_endpoint": "https://sso.aldelo.com/authorize",
"backchannel_logout_session_supported": true,
"backchannel_logout_supported": true,
"claims_supported": [
"sub",
"iss",
"aud",
"exp",
"iat",
"auth_time",
"amr",
"acr",
"sid",
"organization_id",
"email",
"email_verified"
],
"code_challenge_methods_supported": [
"S256"
],
"end_session_endpoint": "https://sso.aldelo.com/logout",
"grant_types_supported": [
"authorization_code"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"introspection_endpoint": "https://sso.aldelo.com/oauth2/introspect",
"issuer": "https://sso.aldelo.com",
"jwks_uri": "https://sso.aldelo.com/.well-known/jwks.json",
"prompt_values_supported": [
"none",
"login",
"select_account"
],
"response_types_supported": [
"code"
],
"revocation_endpoint": "https://sso.aldelo.com/oauth2/revoke",
"subject_types_supported": [
"public"
],
"token_endpoint": "https://sso.aldelo.com/oauth2/token",
"userinfo_endpoint": "https://sso.aldelo.com/userinfo"
}
2. Create a PKCE pair
Every sign-in uses PKCE with the S256 method. For each sign-in, generate a random code_verifier as RFC 7636 describes, and send its SHA-256 hash, base64url-encoded without padding, as the code_challenge. Keep the verifier until the callback.
code_verifier = dBjftJeZ4CVP-mJ92K1uhbDQpBqQ9cHqLhmlUA8OTkY
code_challenge = E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
3. Send the person to sign in
Redirect the browser to the authorization endpoint:
GET https://sso.aldelo.com/authorize
?response_type=code
&client_id=example-app
&redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
&scope=openid%20email
&state=af0ifjsldkj-state
&nonce=n-0S6_WzA2Mj
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
Required parameters:
response_type=code, the only response type.client_idandredirect_uri. The redirect URI must match a registered one exactly.scope: a space-separated subset of the scopes your app is registered for, fromemail,openid,profile. Includeopenidto get an ID token.state: a random value of at least 8 bytes. Check that the callback returns the same value.code_challengeandcode_challenge_method=S256.
Optional parameters:
nonce(recommended): 8 to 512 bytes. It comes back in the ID token so you can tie the token to this request.prompt: one or more ofnone,login,select_account, space-separated.nonemust be sent on its own: it signs the person in silently or returns an error, and never shows a page.max_age: the longest time, in seconds, since the person last signed in. If their session is older, they sign in again.acr_values: the authentication strength you need. See Tokens and claims.organization_hint: for apps that serve several organizations. See Organizations.
A bad request stays on SSO
If a request is malformed, or its redirect URI isn't registered, SSO shows an error page instead of redirecting. That protects your users from open redirects. See Errors.
4. Handle the callback
After sign-in, SSO redirects to your redirect URI with a one-time code and your state:
GET https://app.example.com/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=af0ifjsldkj-state
Check that state matches what you sent, then exchange the code straight away: codes are single-use and short-lived. If the callback carries error instead of code, see Errors.
5. Exchange the code for tokens
From your server, post the code to the token endpoint. A server-side app authenticates with its client secret, either in the Authorization header (client_secret_basic, shown here) or as client_id and client_secret form fields (client_secret_post).
curl -X POST https://sso.aldelo.com/oauth2/token \
-u 'example-app:YOUR_CLIENT_SECRET' \
-d grant_type=authorization_code \
-d code=SplxlOBeZQQYbYS6WxSbIA \
--data-urlencode redirect_uri=https://app.example.com/callback \
-d code_verifier=dBjftJeZ4CVP-mJ92K1uhbDQpBqQ9cHqLhmlUA8OTkY
A public client sends no secret and no Authorization header. It sends client_id=example-app as a form field instead; PKCE is its proof.
{
"access_token": "eyJhbGciOiJSUzI1NiJ9.example.signature",
"expires_in": 600,
"id_token": "eyJhbGciOiJSUzI1NiJ9.example.signature",
"scope": "openid email",
"token_type": "bearer"
}
expires_in is your app's access-token lifetime: 600 seconds unless your registration sets another value. There is no refresh token. When the access token expires, sign the person in again; if their SSO session is still live, prompt=none does it without a page.
6. Validate the ID token
Before you trust the ID token, check its signature, issuer, audience, expiry and nonce; Tokens and claims lists every check. Then use sub as the person's stable ID and organization_id as the organization they signed in to.
7. Read the person's claims
Call /userinfo with the access token when you need the person's email address, or to confirm that their session is still live:
curl https://sso.aldelo.com/userinfo \
-H 'Authorization: Bearer ACCESS_TOKEN'
{
"email": "person@example.com",
"email_verified": true,
"organization_id": "00000000-0000-0000-0000-000000000000",
"sub": "00000000-0000-0000-0000-000000000000"
}
Next steps
- Organizations: which organization a sign-in carries, and how people switch.
- Sessions and logout: sign people out, and hear when their session ends.
- Errors: everything your callback and API calls can return.