PUT methods/{name}/ and {"enabled": true} on your application’s Authentication management API, or from the console. Hosted sign-in shows only the methods you enabled.
Each JSON call below starts with a
transaction from POST authorize/. That transaction lasts 10 minutes. A successful sign-in returns {code, redirect_uri, state}. Exchange the code at POST token/ within 60 seconds (see tokens and JWKS).
Instead of a code, a sign-in call can return one of these steps. Finish the step, then you receive the code.
Password
POST password/ takes transaction, email and password.
- A password must meet your
password_min_length(8, 10, 12 or 14 characters; 10 by default). Common and all-numeric passwords are rejected withpassword_policy. When the breached-password check is on, a known breached password is rejected withpassword_breached. - Only people with a verified email can sign in with a password.
- A wrong password, an unknown email, an unverified email, a locked account and a blocked account all get the same answer:
400 {"error": "invalid_credentials"}. Your UI cannot tell which one it was, and neither can an attacker.
Sign-up
Sign-up verifies the email first. CallPOST email/start/ with purpose: "signup", email and password, then POST email/complete/ with the code. The account is created with a verified email.
signup_policydecides who can sign up:anyone,invited(only with an invitation link) orallowed_domains.- With
allow_subaddresses: false(the default), an address with+in the local part is rejected. - When your branding sets terms or privacy links, the hosted sign-up form asks the person to accept them.
Email code
POST email/start/ takes transaction, purpose (login or signup) and email, and returns 202 {challenge, expires_in: 600}. The person receives a 6-digit code that lasts 10 minutes.
POST email/complete/ takes transaction, purpose, challenge and code. You get 5 attempts, then the person must request a new code. The hosted page offers a new code after 30 seconds.
A login code for an address with no account creates one when your signup_policy allows it. This is passwordless sign-up.
Magic link
The hosted page sends a sign-in link that lasts 15 minutes. It stays tied to the original PKCE transaction, so the link works only in the flow that started it. The person confirms the sign-in on the page the link opens. There is no JSON endpoint for magic links.Phone code
POST phone/start/ takes transaction, phone and an optional channel (sms, the default, or whatsapp). The number is normalized to E.164. It returns 202 {challenge, expires_in: 600}.
POST phone/complete/ takes transaction, challenge and the 6-digit code. You get 5 attempts.
- Phone codes are delivered through Didit’s phone verification. Enable the method with the
workflow_idof a workflow that contains phone verification. - A first phone sign-in creates an account only when
signup_policyisanyone. - If delivery fails, the call returns
503 {"error": "delivery_unavailable"}.
Passkeys
Passkeys use WebAuthn. The relying party is your application’s sign-in origin. Didit asks for a discoverable credential (resident key) and always requires user verification, such as a fingerprint, face or device PIN. Didit does not ask for attestation.- A passkey challenge lasts 5 minutes.
- Adding a passkey needs a session created within the last 5 minutes. Otherwise the call returns
403 {"error": "reauthentication_required"}. Sign the person in again first. - A passkey sign-in counts as multi-factor.
- After sign-up, the hosted page offers to add a passkey (
passkeys/setup/begin/andpasskeys/setup/complete/). - Android apps registered on the application can use the same passkeys.
Social sign-in
Google, Microsoft, Apple and GitHub sign-in use your own OAuth app credentials, set withPUT methods/{provider}/ and credentials: {client_id, client_secret}. The provider callback is on your sign-in origin.
The first time someone signs in with a provider, they also prove they own the email address with a code (POST social/email/start/ and POST social/email/verify/). Later sign-ins with that provider skip this step.
GitHub cannot prove a recent sign-in, so it is not offered when you send prompt=login or max_age.
Organization SSO
Organization SSO lets a customer’s company sign in through its own SAML or OIDC identity provider. Configure it per customer organization atorganizations/{id}/sso/ with protocol (saml or oidc), enabled and config.
- You can send the customer’s IT team a setup link that lasts 7 days.
- Your SAML service provider metadata is published at
{origin}/sso/saml/metadata/. - Hosted sign-in finds the connection from the person’s verified email domain, or from
organization=<slug>on the sign-in URL.
Didit ID Wallet
People who already verified with Didit can sign in with their Didit ID Wallet. This method is always on. The session’sverified_identity then carries what the person chose to share.
MFA
The second factor is an authenticator app (TOTP) with recovery codes, or a passkey.mfa_policydecides who must use MFA:optional,everyoneororganization_admins(the default). Anyone who has enrolled an authenticator must always use it.- To enroll an authenticator, call
POST mfa/enroll/with a fresh session (created within 5 minutes). It returns{challenge, uri}; show theurias a QR code. Then send the first code toPOST mfa/confirm/. The response holds 10 single-use recovery codes. Show them once. - At sign-in, send a TOTP or recovery code to
POST mfa/complete/with thechallenge. You get 5 attempts. To use a passkey instead, callPOST mfa/passkey/begin/andPOST mfa/passkey/complete/. - Codes use 30-second steps. A code that was already accepted cannot be used again.
- SMS and email codes are not available as second factors.
Forgot and reset password
POST password-reset/start/ takes email and returns 202 {"status": "sent", "expires_in": 1800}. The answer is the same whether or not the address has an account. The reset link lasts 30 minutes.
POST password-reset/complete/ takes token and password and returns {"status": "password_changed"}. It also:
- clears a lockout,
- ends every session when
revoke_on_password_changeis on (the default), - invalidates other pending codes and links for that person.
Invitations
Withsignup_policy: "invited", only invited people can sign up. An invitation link lasts 7 days and opens the hosted /invite page.
Continue with tokens and JWKS, or read bot protection for lockouts and challenges.