Integrationsguide¶
Foretrækker du alt på én side? Se single-page versionen — komprimeret med de vigtigste kode-eksempler.
Kom i gang¶
Før integration skal følgende være på plads:
Forudsætninger¶
- Aftale med MedCom om Keycloak-klient og adgang til VDX Auth API. Se adgangsvejledning og kontakt
vdx@medcom.dk. - Brugeren skal være kendt i VDX (lokal bruger i databasen, eller external bruger via organisationens IdP).
- JWT audience i access token skal matche det forventede audience for miljøet (stage default:
organisation-audience). - CORS og host: Din webapps origin skal whitelistes hos MedCom, hvis browseren kalder API'et direkte (mønster B i Integrationsmønstre).
Miljøer¶
| Miljø | Auth API base URL | Keycloak discovery (stage) |
|---|---|---|
| Stage | https://mgmtauthapi.vconf-stage.dk |
https://login.vconf-stage.dk/auth/realms/broker/.well-known/openid-configuration |
| Produktion | https://mgmtauthapi.vconf.dk |
https://login.vconf.dk/auth/realms/broker/.well-known/openid-configuration |
Bekræft den konkrete produktions-URL og Keycloak-konfiguration hos MedCom.
Autentificering¶
Flow¶
- Log brugeren ind i din webapp via Authorization Code Flow med PKCE mod VDX Keycloak.
- Modtag et access token fra Keycloak efter succesfuldt login.
- Send access token i alle kald til VDX Auth API:
- Forny token via dit OIDC-biblioteks refresh-logik, når access token udløber.
Keycloak OpenID Discovery¶
Stage discovery URL:
Discovery-endpointet returnerer alle relevante OAuth2-URLs (authorization_endpoint, token_endpoint, end_session_endpoint, jwks_uri). Brug det som single source of truth — undgå at hard-code endpoints i din klient.
Applikationsidentitet¶
API'et identificerer kaldende klient via JWT-claim azp (authorized party). Mangler claim, logges "unknown". Feltet application i /v1/user-responsen afspejler typisk samme værdi.
Valgfri header ved autorisationsskift¶
| Header | Beskrivelse |
|---|---|
X-VDX-AuthorizationId |
Heltal > 0 — skifter effektiv gruppe til en autorisation brugeren ejer. Se Autorisationsskift. |
Se også JWT-claims, Login-flow og Fejlkoder.
Integrationsmønstre¶
API'et understøtter kun bruger-bundne JWT'er (Authorization Code + PKCE). "Service-to-service" handler her om hvor i din arkitektur kaldet udføres, ikke om Client Credentials. Vælg ét af to mønstre — mønster A er anbefalet for de fleste server-side webapps:
A) Backend-til-API (anbefalet)¶
Din webapps backend kalder VDX Auth API på vegne af brugeren med dennes access token:
- Brugeren logger ind via Keycloak (PKCE) mod din webapp.
- Access og refresh tokens gemmes server-side (fx i krypteret session/cookie).
- Backend kalder API'et med
Authorization: Bearer <brugerens access_token>via en gen-anvendelig HTTP-klient (timeout 10–30 sek.). - Brugeren ser aldrig access token i browseren.
Fordele: Ingen tokens i browser, ingen CORS-konfiguration, ingen XSS-risiko for tokens, centraliseret fejlhåndtering og caching server-side.
Se Login-flow for den anbefalede sekvens og Best practices for caching.
B) Browser-til-API (direkte fra frontend)¶
SPA-style frontends kan kalde VDX Auth API direkte, hvis:
- Din webapps origin er whitelisted hos MedCom.
- Frontend håndterer Keycloak login (fx via
keycloak-js) og opbevarer tokens (typisk i memory). - Hvert fetch-kald sætter både
Authorizationog evt.X-VDX-AuthorizationIdheaders manuelt.
Ulemper: Tokens skal håndteres sikkert i browseren, CORS skal aftales pr. miljø, og du bærer selv ansvaret for token-refresh.
Hvad er ikke understøttet¶
- OAuth2 Client Credentials Flow (egen system-identitet uden bruger) → afvises med 401. API'et kræver bruger-claims (
dk:medcom:email,dk:medcom:organisation_idm.fl.) i token. - Token-share mellem apps: Hver app har eget Keycloak-klient-ID (
azp); access tokens er bundet til klienten der udstedte dem.
Se også Flow-diagrammer og Kodeeksempler.
Login-flow¶
Et komplet login-flow består af OIDC mod Keycloak efterfulgt af et obligatorisk profil-kald til VDX Auth API. API'et er single source of truth for organisationskontekst — undlad at udlede organisationGroup, organisationName mv. fra JWT-claims selv.
Anbefalet sekvens (mønster A — backend-til-API)¶
- Initier login: Generér PKCE
code_verifier+code_challenge, gemcode_verifierogstatei en krypteret, kortlivet cookie (eller server-side cache). Redirect brugeren til Keycloakauthorization_endpointmedresponse_type=code,code_challenge_method=S256,scope=openid. - Callback: Modtag
code+statefra Keycloak. Validerstatemod værdien gemt i trin 1. - Token-veksling: POST til Keycloak
token_endpointmedgrant_type=authorization_code,code,code_verifier,redirect_uri,client_id. Modtagaccess_token,refresh_token,expires_in. - Hent brugerprofil (obligatorisk): Kald
GET /v1/userstraks efter token-veksling med det nye access token. Hvis dette kald fejler (401,403), skal login afvises — uden et succesfuldt profil-kald har du ikke en gyldig VDX-kontekst. Se GET /v1/user. - Rolle-validering: Læs
roles-feltet fra responsen og afvis brugere uden krævede roller (fxvdx-admin,management-admin,management-readonly). Returnér til login-siden med fejlbesked. - Persister tokens og identitet server-side:
- Access token +
expires_ati session. - Refresh token i en krypteret cookie (HttpOnly, Secure, SameSite=Lax).
- Hold authentication-cookien minimal: gem kun identitet + refresh token. Brugerprofilen hentes live fra
/v1/userpå hvert request (se Best practices). - Redirect til en relevant landing-side i din app (fx den side der viser data for brugerens
organisationGroup).
Token-fornyelse¶
- Tjek
expires_atved hvert request; hvis access token udløber inden for ~60 sekunder, kald Keycloaktoken_endpointmedgrant_type=refresh_token. - Gem rotated refresh token tilbage i persistent storage (Keycloak roterer som standard).
- Hvis refresh fejler → ryd session, log brugeren ud, redirect til login.
Se Kodeeksempler: Token-refresh for Python/C# snippets.
Genopbygning efter pod-skift / app-restart¶
Når in-memory session er væk men auth-cookien stadig holder:
- Læs
refresh_tokenfra cookie (eller anden persistent storage). - Forny tokens via Keycloak
token_endpointmedgrant_type=refresh_token. - Gem nye tokens i (ny) session.
- Næste request rammer
/v1/userog rebuilder brugerprofilen i memory.
Sekvens for mønster B (browser-til-API)¶
Stort set samme flow, men trin 1–3 udføres af et OIDC-bibliotek i frontenden (fx keycloak-js), trin 4 er et HTTP-kald direkte mod v1/user, og trin 6 reduceres til at gemme tokens i memory + håndtere token-refresh client-side.
Se også Flow-diagrammer, Autentificering og Best practices.
Autorisationsskift¶
Headeren X-VDX-AuthorizationId styrer hvilken gruppe brugeren arbejder i, når brugeren har management-autorisationer på andre grupper end egen organisation.
| Header-værdi | Effekt |
|---|---|
Mangler / tom / 0 |
Basis-kontekst (brugerens egen organisation) |
| Gyldigt id > 0 | Effektiv gruppe sættes til autorisationens gruppe |
Vælg autorisation¶
- Hent listen med
GET /v1/user/authorizationsog vis den i UI (fx modal/dropdown). Se endpoint-dokumentation. - Brugeren vælger en post (typisk identificeret ved
groupId). - Valider ved at slå
idop i listen fra trin 1 (sikrer at brugeren ejer autorisationen). - Verificér mod API'et: Kald
GET /v1/usermedX-VDX-AuthorizationId: {id}. Hvis kaldet returnerer403, blev autorisationen afvist — vis fejl uden at skifte kontekst. - Persister valget: Gem
{id, groupId, groupName, roles}i cookie, session eller anden persistent storage så det overlever pod-skift. - Invalidér cache for brugerprofilen (eller stol på cache-nøgle der inkluderer autorisations-ID).
- Send headeren med på alle efterfølgende kald til
/v1/user,/v1/user/group,/v1/user/group/parents.
Eksempel på minimalt persistens-objekt:
Slip autorisation¶
- Fjern persistens: Slet det gemte autorisations-objekt fra cookie/session/state.
- Valgfrit: Kald
GET /v1/userudenX-VDX-AuthorizationId(eller med0) for at sikre basis-kontekst i API'ets session-tracking. - Invalidér cache: Næste
/v1/user-kald uden header får frisk respons medisAuthorization = false. - Redirect brugeren til standard-landing (fx egen organisations side).
Profil i autorisations-kontekst¶
Efter et succesfuldt skift afspejler /v1/user-svaret den nye kontekst:
isAuthorization=trueauthorizationId= det valgte idorganisationGroup= autorisationens gruppe-idorganisationName= autorisationsgruppens navn
Bemærk: /v1/user/authorizations filtreres ikke af headeren — listen er altid den fulde mængde autorisationer brugeren ejer.
Fejl ved autorisationsskift¶
| HTTP | Besked | Handling |
|---|---|---|
| 400 | Invalid X-VDX-AuthorizationId |
Afvis skift, behold eksisterende kontekst |
| 403 | Authorization does not belong to user |
Afvis skift, behold eksisterende kontekst |
I begge tilfælde bør backend ikke logge brugeren ud — kun afvise det nye skift.
Se også Kodeeksempler, UserProfile-modellen og Fejlkoder.
Best practices¶
VDX Auth API er autoritativ for organisationskontekst, gruppe-ID, roller, autorisationsstatus og external user-data. Læg din apps logik op om dette princip.
Hvad du skal bruge fra /v1/user-responsen¶
| Felt | Brug |
|---|---|
organisationId, organisationName |
Vis brugerens organisation i UI, beslut adgang til organisations-specifik data |
organisationGroup |
Den effektive gruppe brugeren arbejder i — brug i alle gruppe-relaterede queries |
organisationGroupOverride |
Sat hvis external bruger er flyttet manuelt; afspejlet allerede i organisationGroup |
isAuthorization, authorizationId |
Vis indikator i UI når brugeren arbejder i autorisations-kontekst |
hasAvailableAuthorizations |
Skjul/vis menu-indgang til autorisationsvælger |
roles |
Komma-separeret rolle-liste — brug til adgangstjek i UI og backend |
userType |
local vs. external |
sessionId, timestamp |
Spor/diagnose; medsend i fejlrapporter |
Se UserProfile-modellen for komplet felt-reference.
Hvad du ikke skal gøre¶
- Ikke udlede organisationskontekst fra JWT-claims direkte. Claims er input; API'et resolver mod databasen, anvender autorisationsskift, external user-override og auto-gruppe-træ.
- Ikke cache
/v1/user-svar længe. Brugerens kontekst kan skifte, og deaktivering i VDX skal slå igennem hurtigt. - Ikke behandle 403 fra
/v1/usersom "retry senere" — det betyder deaktiveret lokal bruger eller ugyldig autorisation. Log brugeren ud.
Anbefalet caching-strategi (mønster A)¶
- Kald
/v1/userén gang per request — fx via HTTP-middleware/filter før din app-logik. - Cache resultatet in-memory med nøgle
user_context:{email}:{authorizationId|"none"}og TTL ~30 sekunder. - Inklusion af autorisations-ID i nøglen giver automatisk nyt cache-segment ved autorisationsskift.
- Læg profilen i request-scope storage, så samme request genbruger én reference.
- Ved fejl (tomt svar eller
403/401) → ryd session, log brugeren ud, redirect til login.
Strikt sikkerhed ved fejl (fail closed)¶
| Status | Reaktion |
|---|---|
200 |
Brug data, opdatér cache |
401 |
Token udløbet/ugyldigt → refresh-forsøg, ellers logud |
403 |
Bruger deaktiveret eller autorisation ugyldig → logud + brugerbesked |
500 / netværksfejl |
Logud + besked "Kunne ikke validere session" |
Felter til persistent state¶
Det er kun nødvendigt at gemme to ting persistent:
- Refresh token — så session kan genopbygges efter app-restart.
- Valgt autorisations-ID — så autorisationsskift overlever pod-skift.
Resten (organisationGroup, organisationName, roles …) hentes live fra API'et via caching ovenfor.
Se også Login-flow og Fejlkoder.