Add sign-in to an app
Sign a person in to your application with OpenID Connect, using the authorization code flow with PKCE, and read who they are.
In this tutorial you sign a person in to an application and read their identity. You use the OpenID Connect authorization code flow with PKCE (RFC 7636), which is the flow every OpenID Connect library implements.
The steps show each request on the wire, so you can see what your library does for you. It takes about ten minutes.
Before you begin
You need:
- An AuthFI project and its issuer, the project's URL. This tutorial uses
https://acme.authfi.io. - Permission to add applications in the AuthFI console.
curlandopenssl, or Node.js 18 or later, or Python 3.
Register your application
- In the console, open Integrations > Applications and select Register.
- Under What are you connecting?, choose OIDC / OAuth 2.0.
- Choose the kind that matches where your code runs:
- Web application runs on your server and can keep a secret.
- Single-page app runs in the browser and proves itself with PKCE instead of a secret.
- Enter a Name. Under Redirect URIs, enter the URL in your application that AuthFI sends the person back to after they sign in. This tutorial uses
https://app.acme.com/callback. Enter one URI per line. - Review the summary and select Register.
The last step shows the application's Client id. A web application also gets a Client secret, shown once: copy it, then tick I have copied the client secret to continue. The same step lists the project's endpoints, under Paste these into the other side.
export CLIENT_ID=<your client ID>Create a PKCE verifier and challenge
PKCE ties the sign-in to the application that started it. You create a random secret, the verifier, and send only its SHA-256 hash, the challenge. Later you prove you hold the verifier.
VERIFIER=$(openssl rand -base64 48 | tr -d '=+/' | cut -c1-64)
CHALLENGE=$(printf '%s' "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')
STATE=$(openssl rand -hex 16)Keep the verifier and state in the person's session on your server. You need both when they come back.
Send the person to sign in
Redirect the browser to the project's authorization endpoint.
GET
/oauth/authorizeecho "https://acme.authfi.io/oauth/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=https%3A%2F%2Fapp.acme.com%2Fcallback&scope=openid%20profile%20email&state=$STATE&code_challenge=$CHALLENGE&code_challenge_method=S256"AuthFI shows your project's sign-in page. To try the flow by hand, open the URL in a browser and sign in.
Receive the authorization code
After the person signs in, the browser returns to your redirect URI:
https://app.acme.com/callback?code=Xq3v...&state=5f2a...&iss=https%3A%2F%2Facme.authfi.ioCompare state with the value you stored. If they differ, stop: the response does not belong to a sign-in you started.
The code works once and expires after 5 minutes.
export CODE=<the code from the URL>Exchange the code for tokens
Send the code and the verifier to the token endpoint. The body is form-encoded.
POST
/oauth/tokencurl https://acme.authfi.io/oauth/token \
-d grant_type=authorization_code \
-d code="$CODE" \
-d redirect_uri=https://app.acme.com/callback \
-d client_id="$CLIENT_ID" \
-d code_verifier="$VERIFIER"A web application also sends its client secret, as HTTP Basic authentication or as client_secret in the body.
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6Ii4uLiJ9...",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "...",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ii4uLiJ9...",
"scope": "openid profile email"
}Validate the ID token
The ID token is a signed JWT. Before you trust it, validate it. An OpenID Connect library does this when you configure it with these values:
The library checks the signature against the project's keys, and checks that iss is your issuer, aud is your client ID and exp is in the future.
The validated token tells you who signed in:
{
"iss": "https://acme.authfi.io",
"sub": "[email protected]",
"aud": "<your client ID>",
"email": "[email protected]",
"email_verified": true,
"name": "Ada Lovelace",
"groups": ["engineering"],
"roles": ["developer"],
"auth_time": 1760000000,
"iat": 1760000000,
"exp": 1760000900
}Check that it works
Call the userinfo endpoint with the access token.
curl https://acme.authfi.io/oauth/userinfo \
-H "Authorization: Bearer $ACCESS_TOKEN"{
"sub": "[email protected]",
"email": "[email protected]",
"email_verified": true,
"name": "Ada Lovelace",
"groups": ["engineering"],
"roles": ["developer"]
}If you see the person you signed in as, the flow works end to end.
Troubleshooting
Every error is listed in the endpoint reference.
Next steps
Sessions, sign-out and MFA
Keep a person signed in with refresh tokens, sign them out, and require multi-factor authentication.
Application types and redirect URIs
Choose the right type, and see how redirect URIs are matched.
Service to service
Get a token for a backend service that has no person to sign in.
Endpoint reference
Every parameter and response of every OAuth and OpenID Connect endpoint.