Process: Authentication Data Flow — Company Representative Authentication Project: Europe Login — Dutch Business Identity & Authentication Platform Owner: GloryLabs Date: 2026-03-27
This document describes how personal data flows through the Europe Login system during the primary authentication flow: a company representative authenticating on behalf of their company to obtain a JWT token at a specified assurance level (BASIS, MIDDEN, or HOOG). It covers data entry points, processing steps, storage locations, third-party interactions, and deletion.
Systems involved:
Data involved:
People involved:
The authentication data flow is triggered when a company representative submits their credentials (e-mail address, password, and optionally a second factor depending on assurance level) via the Europe Login Portal to authenticate on behalf of their company.
A secondary trigger is the registration flow: a company administrator adding or updating a representative record, which triggers BSN ingestion and encryption.
| Step | Actor | Action | System | Output |
|------|-------|--------|--------|--------|
| 1 | Company administrator | Submits representative details (BSN, name, email, role) via portal | Angular frontend | HTTP POST to backend API (TLS) |
| 2 | Backend API | Validates input; checks KvK number format (8 digits) via KvkValidationService | Spring Boot backend | Validation result |
| 3 | Backend API | Calls KvK API with KvK number to confirm company is active | KvK API (external, HTTPS) | Company status (active / inactive) |
| 4 | Backend API | Rejects request if company is inactive | Spring Boot backend | HTTP 400 / error response to frontend |
| 5 | Backend API | Encrypts BSN using AES with bsn-encryption-key (from Kubernetes Secret / env var) | Spring Boot backend (in-memory) | AES ciphertext of BSN |
| 6 | Backend API | Persists representative record (encrypted BSN, name, email, role, KvK number) to PostgreSQL | PostgreSQL | Representative record stored |
| 7 | Backend API | Returns success response (no BSN in response) | Spring Boot backend | HTTP 201; BSN not included in response |
| Step | Actor | Action | System | Output |
|------|-------|--------|--------|--------|
| 1 | Company representative | Submits email, password (and 2FA if MIDDEN/HOOG) via login form | Angular frontend | HTTP POST to /auth/login (TLS) |
| 2 | Backend API | Validates credentials against PostgreSQL representative record | Spring Boot + PostgreSQL | Authentication result (pass / fail) |
| 3 | Backend API | Calls KvK API with KvK number to confirm company is still active | KvK API (external, HTTPS) | Company status |
| 4 | Backend API | Rejects authentication if company is inactive | Spring Boot backend | HTTP 401 / error response |
| 5 | Backend API | Decrypts BSN from PostgreSQL using AES key (in-memory only; never persisted or logged in plaintext) | Spring Boot backend (in-memory) | Plaintext BSN in memory |
| 6 | Backend API | Evaluates assurance level requirements; verifies 2FA token if MIDDEN or HOOG | Spring Boot backend | Assurance level confirmed |
| 7 | Backend API | Issues signed JWT containing: subject (user identifier), KvK number, role, assurance level, expiry; BSN is NOT included in JWT | Spring Boot backend | Signed JWT token |
| 8 | Backend API | Stores session metadata (session ID, token expiry, revocation flag) in Redis with TTL | Redis | Session entry (max 24h TTL) |
| 9 | Backend API | Logs authentication event (timestamp, KvK number, assurance level, IP, result) — no BSN in log | Application log / audit log | Audit entry |
| 10 | Backend API | Returns JWT to frontend | Spring Boot backend | HTTP 200 + JWT |
| 11 | Angular frontend | Passes JWT to relying party / stores in secure context | Browser / relying party | Authenticated session |
| Step | Actor | Action | System | Output | |------|-------|--------|--------|--------| | 1 | Relying party | Presents JWT to Europe Login validation endpoint (or validates locally using public key) | Relying party + Spring Boot backend | JWT validation request | | 2 | Backend API | Verifies JWT signature, expiry, and checks Redis revocation list | Spring Boot + Redis | Valid / revoked / expired | | 3 | Backend API | Returns validation result and decoded claims (KvK number, role, assurance level) | Spring Boot backend | Claims or rejection |
| Step | Actor | Action | System | Output | |------|-------|--------|--------|--------| | 1 | Company representative or system | Initiates logout or token expiry reached | Angular frontend / timer | Logout request | | 2 | Backend API | Adds JWT ID to Redis revocation list | Redis | Token marked as revoked | | 3 | Redis | Session entry expires automatically via TTL (max 24h) | Redis | Session data deleted |
[Company Representative]
│
│ email + password (+ 2FA)
▼
[Angular Frontend] ──── HTTPS/TLS ────► [Spring Boot Backend API]
│
┌──────────────────────┤
│ │
▼ ▼
[PostgreSQL] [KvK API (external)]
- encrypted BSN - company status lookup
- representative data - KvK number only sent
- KvK number - no personal data sent
- role
│
▼
[AES decryption (in-memory)]
BSN plaintext exists only
transiently in JVM heap
— never logged, never in JWT
│
▼
[JWT issued]
Contains: subject, KvK, role,
assurance level, expiry
Does NOT contain: BSN, name
│
┌──────────┴──────────┐
▼ ▼
[Redis] [Relying Party]
session cache receives JWT
TTL 24h validates claims
revocation list
Data that leaves the system boundary:
Data that never leaves the system boundary:
Storage locations (all in NL, TransIP VPS):
| Failure scenario | Behaviour | Data implications | |-----------------|-----------|-------------------| | Invalid KvK number format | Rejected at input validation; no KvK API call made | No data stored or transmitted | | KvK API returns inactive company | Authentication rejected with HTTP 401; authentication failure logged | No token issued; failure logged without BSN | | KvK API unavailable / timeout | Authentication rejected with HTTP 503; event logged | No token issued; system treats unavailability as a blocking error (no fallback to cached status) to prevent authentication with stale company data | | Invalid credentials | HTTP 401 returned; failed attempt logged with timestamp and IP | BSN decryption not attempted for failed credential check | | 2FA failure (MIDDEN/HOOG) | HTTP 401 returned; failed attempt logged | Token not issued; assurance level not downgraded silently | | BSN decryption failure (key unavailable) | HTTP 500; critical alert; authentication blocked | BSN plaintext never exposed; system fails closed | | Redis unavailable | Authentication proceeds but session not cached; token still valid (stateless JWT); revocation list unavailable — token cannot be revoked until Redis recovers | Degraded security posture; incident to be raised | | PostgreSQL unavailable | Authentication fails; HTTP 503 | No data exposure; system fails closed |
/Users/sarkout/projects/prive/ocs/europeLogin/dpia.md — Data Protection Impact Assessment/Users/sarkout/projects/prive/ocs/europeLogin/verwerkingsregister.md — Art. 30 GDPR processing register/Users/sarkout/projects/prive/ocs/europeLogin/nis2.md — NIS2 assessment/Users/sarkout/projects/prive/ocs/europeLogin/bio.md — BIO assessment/Users/sarkout/projects/prive/europeLogin/CLAUDE.md — Project rules, secrets management, domain rules
Reacties