Implementation of the MitID / OpenID login flow in the Self Service application.

All endpoints are under /api/{apiVersion}/{organisation}.

Scope: This document describes the MitID (OpenID) login provider. The application has other providers (a planned email-code login) that are out of scope here — they converge on the same final step (Establish session) and share the same session store, so downstream services authenticate uniformly regardless of provider.

Steps

1. Start

POST /auth/openid with a redirect_uri. Receive { ref, openUri }.

Direct the browser to openUri.

2. Authenticate

User completes MitID. Bright binds the authenticated identity to the ref server-side (the CPR/identity is resolved from the ref; the client never handles it).

3. Poll status

Poll POST /accounts/status with { ref } on a fixed interval, branching on status:

StatusMeaningAction
authProgressAuthentication still in progressTransient — keep polling
accountCreatingAccount being createdTransient — keep polling
existsIdentity is linked to an accountProceed to Exchange for session
notInBrightIdentity not yet known to BrightPOST /accounts/create { ref }, then keep polling
needsAssociationIdentity must be linked to a customerCollect customerId + pinCode, POST /accounts/associate { ref, customerId, pinCode }, then keep polling
notCustomerNot a customer of this organisationTerminate
errorAuthentication failedTerminate — surface message

Guards (one action per ref):

4. Loop bound

Cap polling with a max iteration count + delay. If no terminal state is reached, throw a timeout. (Currently: 60 iterations × 2 s ≈ 120 s ceiling.)

5. Exchange for session

POST /sessions/access-token with { ref }. Take the first token's accessToken / refreshToken / userId.

6. Establish session

GET /users/{userId} with the bearer token to resolve accountId (first account), then hand (accessToken, refreshToken, userId, accountId) to the shared session store. Downstream services authenticate via that store regardless of provider.

Flowchart