Skip to main content
Get a working BankID login in about ten minutes. This guide uses OpenID Connect, which is what most integrations should use — if you would rather make two REST calls, see the Session API.

Prerequisites

  • sajn Login enabled for your organization (our team does this — see Overview)
  • An approved client with its client_id and secret. Create one under Inställningar → Utvecklare → sajn Login, then submit it for review.
  • A redirect URI registered on that client. Use http://localhost:3000/callback while developing — plain http is accepted on localhost only.
Point your client at a test certificate while integrating. Test clients accept only test BankIDs from demo.bankid.com and can never authenticate a real person. See Testing.

Use a library, if you can

sajn Login is a standard OIDC provider. Most frameworks need only the issuer URL:
PKCE is mandatory, including for confidential clients. Most libraries enable it automatically; if yours does not, turn it on or /oidc/authorize will reject the request.
If you are using a library, you are done — skip to Use the result. The rest of this page shows the raw flow.

1. Send the user to authorize

Generate a PKCE verifier and challenge, keep the verifier server-side, then redirect:
Generating the PKCE pair
The user lands on the sajn login page, scans with BankID, and is redirected back.

2. Receive the code

Check state matches what you stored. If the login failed, you get ?error=… instead — see Errors.

3. Exchange the code, from your server

Response
The code is single-use and valid for 60 seconds. Exchanging it twice fails — that is deliberate, so a stolen code cannot be replayed.

4. Use the result

Validate the id_token against our JWKS and read the claims:
Always verify the signature, iss, aud, exp and — if you sent one — nonce. Never trust an unverified token, and never trust the browser redirect on its own.
Key your users on sub, not the personnummer. It is stable for that person across all your applications, and it keeps you from storing a national ID number you may not need.

Common mistakes

https redirect URIs must match exactly — no extra path, no trailing slash, no query string. https://app.acme.se/callback does not match https://app.acme.se/callback/.
PKCE is mandatory for every client. Enable it in your library.
The client is not approved yet, or sajn Login is not enabled for the organization. Both are checked before the user ever sees BankID.
The code was already used, expired after 60 seconds, or redirect_uri does not match the one from the authorize request. It must be byte-identical.
If they closed the browser after BankID, the redirect never fired. Subscribe to the login.completed webhook to catch that case.

Next steps

OpenID Connect reference

Every endpoint and parameter in detail

Scopes and claims

What you can request, and what you get

Testing

Create a test BankID and run the flow end to end

Webhooks

Catch logins whose redirect never arrives