eID API Reference
All frontend API endpoints are handled by the eID dispatcher at
/?e. The action query parameter selects the
controller action. Request bodies are JSON. All responses are JSON with
Content-.
Token-based login flow
Both passkey login and recovery code login use a two-phase flow:
- eID verification -- JavaScript calls the eID endpoint
(
loginorVerify recovery). The server verifies the assertion or recovery code and stores the authenticatedVerify fe_UID in a short-lived cache entry (user nr_cache, 2-minute TTL). The response includes apasskeys_ fe_ nonce login.Token - felogin form submission -- JavaScript submits a standard
logintype=loginform to the current page, including theloginin a hidden field. TYPO3's normal FE authentication chain processes the request.Token - Auth service --
Passkey(priority 80) reads theFrontend Authentication Service login, looks up the user UID in the cache, and returns theToken fe_row. The token is consumed (one-time use).users
This ensures users get a proper TYPO3 frontend session with all middleware (enforcement interstitial, session regeneration) applied.
Authentication endpoints (public)
These endpoints do not require a frontend session.
POST /?eID=nr_passkeys_fe&action=loginOptions
Request challenge options for passkey login.
Request:
{
"username": "johndoe"
}
For discoverable login, omit username or send an empty body.
Response (200):
{
"options": {
"challenge": "...",
"rpId": "example.com",
"allowCredentials": []
},
"challengeToken": "..."
}
POST /?eID=nr_passkeys_fe&action=loginVerify
Verify a passkey assertion and issue a login token.
Request:
{
"assertion": {
"id": "...",
"type": "public-key",
"response": {
"clientDataJSON": "...",
"authenticatorData": "...",
"signature": "...",
"userHandle": "..."
}
},
"challengeToken": "..."
}
Response (200):
{
"status": "ok",
"feUserUid": 42,
"loginToken": "abc123..."
}
The login is a one-time token valid for 2 minutes. The
JavaScript must submit it via a standard felogin form to complete the
login (see Token-based login flow above).
Recovery code endpoint (public)
POST /?eID=nr_passkeys_fe&action=recoveryVerify
Login using a one-time recovery code.
Request:
{
"username": "johndoe",
"code": "XXXX-XXXX"
}
Response (200):
{
"status": "ok",
"feUserUid": 42,
"loginToken": "abc123..."
}
The login is consumed via felogin form submission, identical
to the passkey login flow.
Enrollment endpoints (requires session)
POST /?eID=nr_passkeys_fe&action=registrationOptions
Request challenge options for passkey enrollment. Requires an active frontend session.
Response (200):
{
"options": {
"challenge": "...",
"rp": {"id": "example.com", "name": "My Site"},
"user": {"id": "...", "name": "johndoe", "displayName": "John Doe"},
"pubKeyCredParams": [{"type": "public-key", "alg": -7}]
},
"challengeToken": "..."
}
POST /?eID=nr_passkeys_fe&action=registrationVerify
Verify an attestation and save the new credential.
Request:
{
"attestation": {
"id": "...",
"type": "public-key",
"response": {
"clientDataJSON": "...",
"attestationObject": "..."
}
},
"challengeToken": "...",
"name": "My MacBook"
}
Response (200):
{
"status": "ok",
"credentialId": "..."
}
Management endpoints (requires session)
GET /?eID=nr_passkeys_fe&action=manageList
Returns the list of passkeys for the current user.
POST /?eID=nr_passkeys_fe&action=manageRename
Request: {"credential
POST /?eID=nr_passkeys_fe&action=manageRemove
Request: {"credential
POST /?eID=nr_passkeys_fe&action=recoveryGenerate
Generates a new set of 10 recovery codes. Returns the plaintext codes (shown once only).
Response (200):
{
"status": "ok",
"codes": ["XXXX-XXXX", "..."],
"count": 10
}
Enrollment status endpoints (requires session)
GET /?eID=nr_passkeys_fe&action=enrollmentStatus
Returns the current user's enrollment and enforcement status.
POST /?eID=nr_passkeys_fe&action=enrollmentSkip
Skips the enrollment interstitial (only available during grace period
when enforcement level is required).
Action routing summary
The eID dispatcher routes the action query parameter to controllers:
| Action | Controller method | Auth |
|---|---|---|
login | LoginController::optionsAction | Public |
login | LoginController::verifyAction | Public |
recovery | RecoveryController::verifyAction | Public |
recovery | RecoveryController::generateAction | Session |
registration | ManagementController::regOptions | Session |
registration | ManagementController::regVerify | Session |
manage | ManagementController::listAction | Session |
manage | ManagementController::renameAction | Session |
manage | ManagementController::removeAction | Session |
enrollment | EnrollmentController::statusAction | Session |
enrollment | EnrollmentController::skipAction | Session |
Backend AJAX routes
The admin module calls these routes through TYPO3..
Each URL carries the route token TYPO3 issues to the backend session, and
every action answers 403 unless the backend user is an administrator.
| Route | Method | Parameters |
|---|---|---|
nr_ | GET | fe (query argument) |
nr_ | POST | fe, credential |
nr_ | POST | fe |
nr_ | POST | fe, username |
nr_ | POST | group, enforcement |
nr_ | POST | fe |
nr_ accepts off, encourage,
required and enforced, answers 400 for any other value or a
group uid that is not a plain positive integer, 404 for an unknown or
deleted group, and 409 while the administrator works in a workspace
without live editing (fe_ is not versioned). It writes
fe_ through DataHandler, so the change appears
in the record history and the system log.
nr_ sets
fe_ of the user to 0, so the next
request the enrollment interstitial handles under required starts a new
grace period. It answers 400 without a fe and 404 for an
unknown user.
Error responses
All error responses follow this format:
{
"error": "Human-readable error message"
}
Common HTTP status codes:
| Code | Meaning |
|---|---|
| 400 | Invalid request (missing/malformed fields) |
| 401 | Not authenticated (session required) |
| 403 | Forbidden (insufficient privileges) |
| 429 | Rate limit exceeded |
| 500 | Internal server error |