The login flow allows users to authenticate and create sessions in Ory Kratos. It supports multiple authentication methods and multi-factor authentication (MFA).
Flow initialization
Login flows can be initiated for browser-based applications or API clients.
Browser flows
Initialize a login flow for browser applications:
curl -X GET \
'https://{project}.projects.oryapis.com/self-service/login/browser' \
-H 'Accept: application/json'
Query parameters:
refresh - Set to true to refresh an existing session and reset the authenticated_at timestamp
aal - Request a specific Authenticator Assurance Level (aal1 or aal2 for MFA)
return_to - URL to redirect to after successful login
login_challenge - Hydra OAuth2 login challenge (when acting as an OAuth2 provider)
organization - Organization ID for multi-tenant deployments
identity_schema - Specific identity schema to use for this flow
Response:
{
"id" : "f8a5c8e9-5b1c-4f8e-9b3a-1e5f7c9d8e6b" ,
"type" : "browser" ,
"expires_at" : "2026-03-03T12:00:00Z" ,
"issued_at" : "2026-03-03T11:00:00Z" ,
"request_url" : "https://{project}.projects.oryapis.com/self-service/login/browser" ,
"ui" : {
"action" : "https://{project}.projects.oryapis.com/self-service/login?flow=f8a5c8e9-5b1c-4f8e-9b3a-1e5f7c9d8e6b" ,
"method" : "POST" ,
"nodes" : [ ... ]
},
"requested_aal" : "aal1" ,
"state" : "choose_method"
}
API flows
For native applications (mobile, desktop, server-to-server):
curl -X GET \
'https://{project}.projects.oryapis.com/self-service/login/api' \
-H 'Accept: application/json'
Additional query parameters:
return_session_token_exchange_code - Request a code to exchange for a session token after login
Authentication methods
The login flow supports multiple authentication strategies that can be combined for MFA.
Password
Authenticate with identifier (email, username) and password:
curl -X POST \
'https://{project}.projects.oryapis.com/self-service/login?flow=<flow_id>' \
-H 'Content-Type: application/json' \
-d '{
"method": "password",
"identifier": "user@example.com",
"password": "your-secure-password"
}'
OIDC (Social sign-in)
Sign in with OAuth2/OIDC providers (Google, GitHub, Microsoft, etc.):
curl -X POST \
'https://{project}.projects.oryapis.com/self-service/login?flow=<flow_id>' \
-H 'Content-Type: application/json' \
-d '{
"method": "oidc",
"provider": "google"
}'
Supported providers include:
Google
GitHub
Microsoft
Apple
GitLab
Generic OIDC providers
Passkeys (WebAuthn)
Authenticate using FIDO2/WebAuthn credentials:
curl -X POST \
'https://{project}.projects.oryapis.com/self-service/login?flow=<flow_id>' \
-H 'Content-Type: application/json' \
-d '{
"method": "passkey",
"passkey_login": "<webauthn_response>"
}'
TOTP (Time-based one-time passwords)
Second factor authentication with authenticator apps:
curl -X POST \
'https://{project}.projects.oryapis.com/self-service/login?flow=<flow_id>' \
-H 'Content-Type: application/json' \
-d '{
"method": "totp",
"totp_code": "123456"
}'
Lookup secrets (Backup codes)
Authenticate using single-use recovery codes:
curl -X POST \
'https://{project}.projects.oryapis.com/self-service/login?flow=<flow_id>' \
-H 'Content-Type: application/json' \
-d '{
"method": "lookup_secret",
"lookup_secret": "backup-code-1234"
}'
WebAuthn
Hardware security keys and platform authenticators:
curl -X POST \
'https://{project}.projects.oryapis.com/self-service/login?flow=<flow_id>' \
-H 'Content-Type: application/json' \
-d '{
"method": "webauthn",
"webauthn_login": "<webauthn_assertion>"
}'
Multi-factor authentication
Request AAL2 (second factor) authentication:
Check current AAL
Verify the user’s current session authenticator assurance level: curl -X GET \
'https://{project}.projects.oryapis.com/sessions/whoami' \
-H 'Cookie: ory_kratos_session=...'
Response includes authenticator_assurance_level: "aal1" or "aal2".
Initialize AAL2 flow
Request an AAL2 login flow: curl -X GET \
'https://{project}.projects.oryapis.com/self-service/login/browser?aal=aal2' \
-H 'Cookie: ory_kratos_session=...'
Complete second factor
Submit the second factor (TOTP, WebAuthn, or lookup secret): curl -X POST \
'https://{project}.projects.oryapis.com/self-service/login?flow=<flow_id>' \
-H 'Content-Type: application/json' \
-H 'Cookie: ory_kratos_session=...' \
-d '{
"method": "totp",
"totp_code": "123456"
}'
AAL2 flows require an active AAL1 session. If no session exists, the request will fail with session_aal1_required.
Session refresh
Refresh an existing session to update the authenticated_at timestamp:
curl -X GET \
'https://{project}.projects.oryapis.com/self-service/login/browser?refresh=true' \
-H 'Cookie: ory_kratos_session=...'
This forces the user to re-authenticate even if they have an active session.
Fetching an existing flow
Retrieve a login flow by its ID:
curl -X GET \
'https://{project}.projects.oryapis.com/self-service/login/flows?id=<flow_id>' \
-H 'Cookie: ory_kratos_session=...'
Error handling
Common error cases:
Status: 400 Bad RequestThe user is already authenticated. Either use ?refresh=true to re-authenticate, ?aal=aal2 to upgrade to MFA, or redirect to the application.
Status: 400 Bad RequestAAL2 was requested but no active session exists. The user must complete AAL1 login first.
Status: 410 GoneThe flow has expired. Initialize a new flow. Browser flows include a redirect_to URL in the error response.
Status: 403 ForbiddenCSRF token validation failed. Ensure cookies are properly forwarded in browser flows.
Complete flow example
Browser flow
API flow
Node.js SDK
# 1. Initialize the flow
curl -X GET 'https://{project}.projects.oryapis.com/self-service/login/browser'
# Browser is redirected to UI with flow ID
# User visits: https://your-app.com/login?flow=<flow_id>
# 2. Fetch the flow
curl -X GET \
'https://{project}.projects.oryapis.com/self-service/login/flows?id=<flow_id>'
# 3. Submit credentials
curl -X POST \
'https://{project}.projects.oryapis.com/self-service/login?flow=<flow_id>' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'method=password&identifier=user@example.com&password=secret&csrf_token=...'
# Browser is redirected with session cookie set
API reference
Endpoint Method Description /self-service/login/browserGET Initialize browser login flow /self-service/login/apiGET Initialize API login flow /self-service/login/flowsGET Get login flow by ID /self-service/loginPOST Submit login flow
All endpoints are defined in selfservice/flow/login/handler.go:44-49