Process: Age Verification Data Flow Project: valideerleeftijd Owner: GloryLabs Date: 2026-03-27
This process describes how personal data moves through the valideerleeftijd age verification flow — from the initial client API request through the PSD2 bank OAuth2 PKCE redirect, birth date retrieval, in-memory age calculation, and result delivery — with explicit documentation of where data is created, used, and discarded.
Systems involved:
Data involved:
People involved:
A client company sends an authenticated POST request to the valideerleeftijd API, supplying a minimum age threshold and a redirect URI, initiating an age verification for one of their users.
| Step | Actor | Action | System | Output | |------|-------|--------|--------|--------| | 1 | Client application | Sends POST /verify with API key, minimum_age, redirect_uri | valideerleeftijd API | Request authenticated; rate limit checked (100 req/min) | | 2 | valideerleeftijd API | Generates session UUID; stores {session_id, minimum_age, redirect_uri, pkce_code_verifier} in Redis with 15-min TTL | Redis | Session record created (no PII) | | 3 | valideerleeftijd API | Returns redirect URL to bank OAuth2 PKCE authorisation endpoint, including session_id as state parameter | Client application | Redirect URL containing session state | | 4 | Client application | Redirects user's browser to bank OAuth2 authorisation URL | User browser | User sees bank login screen | | 5 | End user | Authenticates with bank; grants consent for AISP access (birth date scope) | Bank OAuth2 server (Tink/Klarna) | Bank issues authorisation code | | 6 | Bank OAuth2 server | Redirects browser to valideerleeftijd callback URL with authorisation code and state (session_id) | valideerleeftijd API | Callback received | | 7 | valideerleeftijd API | Validates state (session_id) exists in Redis; exchanges authorisation code for access token via PKCE | Bank OAuth2 server | Bank access token (ephemeral) | | 8 | valideerleeftijd API | Calls bank AISP API with access token to retrieve birth date | Bank AISP API | Birth date returned in memory | | 9 | valideerleeftijd API | Calculates age from birth date; compares to minimum_age from session; produces boolean result | In-memory only | Boolean: age_requirement_met = true/false | | 10 | valideerleeftijd API | Discards birth date and bank access token from memory; deletes Redis session | Redis | No personal data remains | | 11 | valideerleeftijd API | Redirects user's browser to client redirect_uri with boolean result as query parameter | Client application | Client receives age_verified=true/false | | 12 | Client application | Acts on the boolean result (allow/deny access) | Client application | User granted or denied access |
Client App valideerleeftijd API Redis Bank OAuth2 / AISP
| | | |
|-- POST /verify ----------->| | |
| {api_key, min_age, | | |
| redirect_uri} | | |
| |-- STORE session ------>| |
| | {uuid, min_age, | |
| | redirect_uri, | |
| | pkce_verifier} | |
| | TTL=15min | |
|<-- redirect URL -----------| | |
| (bank auth + state) | | |
| | | |
[User browser redirected to bank] | |
| | | |
| | [User authenticates at bank]
| | | |
| |<-- callback -----------| |
| | {code, state=uuid} | |
| | | |
| |-- GET session -------->| |
| |<-- session data -------| |
| | | |
| |-- exchange code -------------------------------->|
| |<-- access_token ---------------------------------|
| | | |
| |-- GET /birth-date -------------------------------->|
| |<-- birth_date [IN MEMORY ONLY] ------------------|
| | | |
| | calculate age | |
| | discard birth_date | |
| | boolean result | |
| | | |
| |-- DELETE session ----->| |
| | | |
|<-- redirect to client -----| | |
| {age_verified=true/false}| | |
Key data protection properties:
| Failure scenario | Response | |-----------------|----------| | Bank OAuth2 server unavailable | API returns 503 to client; session expires after 15 min; user must restart flow | | User denies bank consent | Bank redirects with error=access_denied; API redirects client with age_verified=error; session deleted | | PKCE validation failure / state mismatch | API returns 400; session deleted; potential replay attack logged | | Bank AISP API returns no birth date | API returns age_verified=error to client; no data stored; session deleted | | Redis session expired before callback | API returns 400 (session not found); user must restart flow | | Rate limit exceeded (>100 req/min) | API returns 429 Too Many Requests to client; no session created | | API key invalid or revoked | API returns 401 Unauthorized; no session created |
../dpia.md — Data Protection Impact Assessment for valideerleeftijd../verwerkingsregister.md — Art. 30 GDPR processing register../nis2.md — NIS2 security assessment../bio.md — BIO controls assessment
Reacties