# User login
Use this integration when users sign in to your app with their Done ID account. It uses the OAuth 2.0 authorization code flow. Browser and mobile apps add PKCE.

Before you start, get a client. See [Request a client](/request-a-client).

## Choose a library

Use a certified OIDC library. Do not write the flow yourself. Configure the library with the issuer URL, and it reads the endpoints from the OIDC configuration.

| Platform | Library examples |
|---|---|
| Browser (SPA) | `oidc-client-ts`, `keycloak-js` |
| iOS | AppAuth-iOS |
| Android | AppAuth-Android |
| .NET | `Microsoft.AspNetCore.Authentication.OpenIdConnect` |
| Node.js | `openid-client` |

The Done OS web app uses `keycloak-js` with PKCE. It is a working example of the browser login.

## How the flow works

1. Your app sends the user to the authorization endpoint of Done ID.
2. The user signs in on the Done ID login page.
3. Done ID sends the user back to your redirect URI with a one-time `code`.
4. Your app sends the `code` to the token endpoint and receives tokens.
5. Your app uses the access token to call APIs and uses the ID token to identify the user.

## Send the user to Done ID

Send the user to `<issuer>/protocol/openid-connect/auth` with these parameters:

| Parameter | Value |
|---|---|
| `client_id` | Your client ID |
| `response_type` | `code` |
| `redirect_uri` | One of the redirect URIs of your client |
| `scope` | `openid` and the other scopes that you need. See [Scopes](#scopes). |
| `state` | A random value. Your app compares it when the user comes back. |
| `code_challenge` | Browser and mobile apps: the PKCE challenge |
| `code_challenge_method` | Browser and mobile apps: `S256` |

Done ID accepts only the `S256` PKCE method for browser and mobile clients.

## Get the tokens

Send a `POST` request to `<issuer>/protocol/openid-connect/token` with `Content-Type: application/x-www-form-urlencoded`:

| Parameter | Server-side login | Browser or mobile login |
|---|---|---|
| `grant_type` | `authorization_code` | `authorization_code` |
| `code` | The code from the redirect | The code from the redirect |
| `redirect_uri` | The same URI as in the login request | The same URI as in the login request |
| `client_id` | Your client ID | Your client ID |
| `client_secret` | Your client secret | Do not send |
| `code_verifier` | Do not send | The PKCE verifier |

A server-side client can also send the client ID and the secret in an HTTP Basic `Authorization` header (`client_secret_basic`) instead of in the body (`client_secret_post`). Done ID accepts both.

The response contains an `access_token`, an `id_token`, a `refresh_token`, and `expires_in`. See [Tokens](/tokens) for the contents and the lifetimes.

## Refresh the session

The access token expires after a short time. Before it expires, send a `POST` request to the token endpoint with `grant_type=refresh_token` and the `refresh_token`. A server-side client also sends its `client_secret`.

If the refresh fails, the Done ID session ended. Send the user to the login page again.

## Scopes

Always request `openid`. These scopes are available:

| Scope | Adds |
|---|---|
| `profile` | Name and username |
| `email` | `email` and `email_verified` |
| `legal-entity.organization` | The user selects a company, and the token contains the company. |
| `legal-entity.individual` | The user selects a private person, and the token contains the person. |

If you request `legal-entity.organization` or `legal-entity.individual`, Done ID shows a selection page after login. The user selects the company or the person that the session is for. If you request both scopes, the user can select from both.

Ask the Done team which scopes your client has. A request for a scope that your client does not have fails with the error `invalid_scope`.

## Require BankID

Done ID has two authentication levels:

| ACR value | Level |
|---|---|
| `urn:done:acr:basic` | Email and password, or another login method |
| `urn:done:acr:strong` | BankID |

If your app needs strong authentication, add `acr_values=urn:done:acr:strong` to the login request. Done ID then shows only BankID login methods and hides the password form.

The `acr` claim in the token shows the level of the login. If your app needs strong authentication, make sure that the claim is `urn:done:acr:strong` before you give access.

## Change the login page

You can add these parameters to the login request to change the Done ID login page:

| Parameter | Effect |
|---|---|
| `ui_locales` | The language of the page, for example `sv` or `en`. |
| `login_hint` | Fills in the email field. |
| `done_country` | Sets the country of the user, for example `Sweden`. By default, Done ID detects the country. |
| `done_bankid_by_country=true` | Shows the BankID of the country of the user as the first login method. |
| `done_hide_elements` | Hides elements. Give a comma-separated list without spaces. |

These are the elements that you can hide:

| Element ID | Element |
|---|---|
| `social-bankid` | Swedish BankID button |
| `social-norwegian-bankid` | Norwegian BankID button |
| `social-microsoft` | Microsoft login button |
| `kc-form-login` | Email and password form |

## Log out

To end the Done ID session, send the user to `<issuer>/protocol/openid-connect/logout` with these parameters:

| Parameter | Value |
|---|---|
| `id_token_hint` | The ID token of the user |
| `post_logout_redirect_uri` | One of the post-logout redirect URIs of your client |
| `client_id` | Your client ID |

If your app keeps a refresh token, revoke it before logout. Send a `POST` request to `<issuer>/protocol/openid-connect/revoke` with `token`, `token_type_hint=refresh_token`, and `client_id`. A server-side client also sends its `client_secret`.

Logout ends the Done ID session for all Done OS apps. After logout, the other apps cannot refresh their tokens, and the user must sign in again.

## Single sign-on

All Done OS apps share one Done ID session. If the user already signed in to another Done OS app, Done ID does not show the login page again. Done ID sends the user directly back to your app with a code.

## Mobile apps

Follow RFC 8252 (OAuth 2.0 for native apps):

1. Open the login page in the system browser (`ASWebAuthenticationSession` on iOS, Custom Tabs on Android). Do not use an embedded web view.
2. Use PKCE with `S256`.
3. Use a claimed HTTPS redirect URI or a custom scheme that you own.
4. Keep the refresh token in the secure storage of the device (Keychain on iOS, Keystore on Android).

## See also

- [Done ID for partner apps](/)
