Go to developer

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     │                        │
     │◄──────────────────────┤                        │
Enrollment sequence

Start enrollment

SERVERTypeScript
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
JSON
{
  "identityId": "kid_…",
  "enrollmentId": "…",
  "status": "pending",
  "expiresIn": 600,
  "enrollmentUrl": "https://get-started.keyra.ie/?enroll=…",
  "pollUrl": "/v1/identities/enroll/…/status"
}
FieldTypeDescription
identityIdstringKEYRA identity id (kid_*).
enrollmentIdstringId used for status polling.
statusstringStarts as pending.
expiresInnumberSeconds remaining (600 at creation).
enrollmentUrlstringUser-facing URL to open or encode as QR.
qrCodestring (SDK)Alias of enrollmentUrl — not a PNG.
pollUrlstringRelative status path for REST clients.

QR rendering

SERVER (or trusted BFF)TypeScript
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

SERVERTypeScript
// 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 (unless already_enrolled).

What to store

  • Store your externalUserId (you already have it).
  • Optionally cache identityId after completion for support tooling.
  • Do not treat enrollment URLs or QR payloads as long-lived secrets to persist.
  • Do not store clientSecret in the browser or mobile app.

Try enrollment in Playground →