- EJS 44.8%
- JavaScript 34.2%
- CSS 19.8%
- Dockerfile 1.2%
| app | ||
| .dockerignore | ||
| .env.example | ||
| docker-compose.yml | ||
| README.md | ||
ID Austria OIDC Test Client
A minimal Node.js OIDC test client for the ID Austria reference environment (idp.ref.id-austria.gv.at).
Implements the Authorization Code Flow, displays all returned claims (including Austria-specific claims like bPK, eIDAS level, and PVP version), and handles iOS Safari's ITP cookie restrictions via a state-encoded session strategy.
Features
| Feature | Details |
|---|---|
| Flow | Authorization Code (response_type=code) |
| Auth method | client_secret_post — required by ID Austria |
client_id format |
URL (required by ID Austria) |
| Scopes | openid profile |
| Logout | RP-Initiated Logout via end_session_endpoint |
| Session strategy | State-encoded (cookie-independent, iOS Safari ITP-compatible) |
| Claims display | All ID Austria claims: bPK, eIDAS level, PVP version, representation/Vollmacht claims |
| Debug endpoint | /debug/discovery — OIDC Discovery metadata as JSON |
ID Austria Specifics
client_secretis mandatory — even without PKCE. Public clients are not supported.client_idmust be a URL — e.g.https://idaustria-test.example.comrequest_uriis not supported — results in an errorresponse_mode=form_postis not supported — results in an errorsubis transient — use thebPKclaim for persistent user identification- No
noncein id_token — do not send anoncein the authorization request - Discovery URL (reference env):
https://idp.ref.id-austria.gv.at/.well-known/openid-configuration
iOS Safari / App2App (Simplified Continuation)
Standard session-over-cookie fails on iOS Safari due to ITP: the callback request arrives without the session cookie, breaking the OIDC state check. This client works around this by encoding the session ID (HMAC-secured with a nonce) inside the state parameter. The callback reconstructs the session from state directly, without relying on a cookie.
Quick Start
1. Register in IDA-SPR
Go to the IDA-SPR and create a new service provider:
| Field | Value |
|---|---|
Application identifier (client_id) |
https://your-domain.example.com |
redirect_uri |
https://your-domain.example.com/callback |
post_logout_redirect_uri |
https://your-domain.example.com/ |
| Test identities | enable |
Save the generated client_secret immediately — it is shown only once.
2. Configure
cp .env.example .env
Edit .env:
- Set
APP_DOMAINto your domain (withouthttps://) - Set
OIDC_CLIENT_SECRETto the secret from IDA-SPR - Generate
SESSION_SECRETwithopenssl rand -hex 32
3. Run
With Traefik (the default docker-compose.yml includes Traefik labels for automatic TLS via Let's Encrypt):
docker compose up -d
docker compose logs -f
Standalone (without Traefik, for local development):
docker build -t idaustria-client ./app
docker run --rm -p 3000:3000 \
-e APP_DOMAIN=localhost:3000 \
-e OIDC_CLIENT_SECRET=your_secret \
-e SESSION_SECRET=$(openssl rand -hex 32) \
-e TRUST_PROXY=false \
idaustria-client
4. Test
- Create a test identity in the Test Identity Manager
- Open
https://your-domain.example.com→ click Anmelden - Authenticate with the test identity
Mobile / Simplified Continuation (App2App):
- Open the ID Austria app → Info → tap the version number 10× → enable Developer functions
- Set Backend environment to Referenz → re-link the app
- Open the test client on your mobile device → tap Anmelden → the app launches automatically
Endpoints
| URL | Description |
|---|---|
/ |
Landing page / claims display after login |
/login |
Initiate login (redirect to IdP) |
/callback |
OIDC callback — register this URL in IDA-SPR |
/logout |
RP-Initiated Logout |
/debug/discovery |
OIDC Discovery metadata (JSON) |
/health |
Health check |
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
APP_DOMAIN |
Yes | — | Domain, e.g. idaustria-test.example.com (without https://) |
OIDC_CLIENT_SECRET |
Yes | — | From IDA-SPR |
SESSION_SECRET |
Yes | random | Session signing secret — openssl rand -hex 32 |
OIDC_ISSUER_URL |
No | Reference env | OIDC Discovery endpoint |
TRUST_PROXY |
No | true |
Trust X-Forwarded-* headers from a reverse proxy |
PORT |
No | 3000 |
HTTP listen port |
OIDC_CLIENT_ID,OIDC_REDIRECT_URI, andOIDC_POST_LOGOUT_URIare derived fromAPP_DOMAINbydocker-compose.yml. You can override them individually if needed (e.g. when running without Docker Compose).
ID Austria Error Codes
These appear as error_description in the callback when a flow fails:
| Code | Cause |
|---|---|
UserCancel |
User cancelled the flow |
UserNotLoggedIn |
ID Austria app not linked to an account |
UserLoggedOut |
Logged out for security reasons |
UserLockedOut |
Too many failed attempts |
SystemInMaintenance |
Scheduled maintenance |
SystemNotReachable |
No internet connection |
Stack
- Runtime: Node.js 24 (Alpine)
- Framework: Express 5
- OIDC: openid-client v6
- Sessions: express-session (in-memory store — restart clears sessions)