Enrollment
Enrollment connects your application user (externalUserId) to a KEYRA identity and verification factor.
On this page
When enrollment is required
Call get2FAStatus. If enrolled is false (identity status none or not active), run enrollment before authentication challenges.
YOUR BACKEND KEYRA USER DEVICE
│ │ │
│ enable2FA(userId) │ │
├──────────────────────►│ │
│ enrollmentUrl / qrCode│ │
│◄──────────────────────┤ │
│ Show QR to user │ │
│ │◄─── open enrollment ───┤
│ │──── verify factor ────►│
│ waitForEnrollment │ │
│──────────────────────►│ │
│ status: completed │ │
│◄──────────────────────┤ │Start enrollment
const enrollment = await keyra.enable2FA(externalUserId, {
// optional: HTTPS URL allowed by your project callback configuration
returnUrl: "https://app.example.com/settings/2fa-done",
});What happens here? KEYRA creates (or resumes) an identity for projectId + externalUserId, returns a pending enrollment session with a user-facing URL, and starts a 600-second timer.
If already active: HTTP 409 already_enrolled.
Enrollment response
responseResponse
{
"identityId": "kid_…",
"enrollmentId": "…",
"status": "pending",
"expiresIn": 600,
"enrollmentUrl": "https://get-started.keyra.ie/?enroll=…",
"pollUrl": "/v1/identities/enroll/…/status"
}| Field | Type | Description |
|---|---|---|
identityId | string | KEYRA identity id (kid_*). |
enrollmentId | string | Id used for status polling. |
status | string | Starts as pending. |
expiresIn | number | Seconds remaining (600 at creation). |
enrollmentUrl | string | User-facing URL to open or encode as QR. |
qrCode | string (SDK) | Alias of enrollmentUrl — not a PNG. |
pollUrl | string | Relative status path for REST clients. |
QR rendering
import QRCode from "qrcode";
const qrDataUrl = await QRCode.toDataURL(enrollment.qrCode);
// Return qrDataUrl to the browser for <img src={qrDataUrl} />Mobile users can also open enrollmentUrl directly. Your UI should keep the enrollment session id so the backend can poll the same enrollment.
Polling
// Helper (default timeout 10m, interval 1.5s)
const done = await keyra.waitForEnrollment(enrollment.enrollmentId);
// Or manual:
const snap = await keyra.pollEnrollment(enrollment.enrollmentId);
// snap.terminal?: "COMPLETED" | "EXPIRED" | "FAILED" | "CANCELLED"Defaults: timeout 600s, interval 1500ms. Override with timeoutMs / intervalMs.
States & expiration
- API enrollment statuses include
pending,phone_sent,completed,expired,cancelled. - SDK
terminal:COMPLETED,EXPIRED,FAILED,CANCELLED. - Expired/cancelled/failed: start a new
enable2FA(unlessalready_enrolled).
What to store
- Store your
externalUserId(you already have it). - Optionally cache
identityIdafter completion for support tooling. - Do not treat enrollment URLs or QR payloads as long-lived secrets to persist.
- Do not store
clientSecretin the browser or mobile app.
