Skip to content

Resource Owner Password Credentials

The Resource Owner Password Credentials (ROPC) grant allows a client to exchange a username and password directly for tokens, without going through the browser authorization flow.

Terminal window
curl -X POST https://auth.example.com/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "username=alice" \
-d "password=secret" \
-d "client_id=my-client-id" \
-d "scope=openid profile email" \
-d "totp_code=123456"
Parameter Required Description
grant_type Yes Must be password
username Yes The user’s username
password Yes The user’s password
client_id Yes The client identifier
scope No Space-separated list of scopes (defaults to client’s allowed scopes, or openid profile email)
totp_code Conditional Required when MFA is enforced (see MFA enforcement below)

Response:

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900,
"scope": "openid profile email"
}

The client must have password in its grant_types. When registering:

Terminal window
curl -X POST https://auth.example.com/oauth2/register \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"client_name": "My CLI Tool",
"redirect_uris": ["http://localhost"],
"grant_types": ["password", "refresh_token"],
"client_type": "public"
}'

MFA is fully enforced in the ROPC flow. When the global require_mfa setting is enabled or the user has TOTP enrolled, the totp_code parameter is required. The server responds with specific error codes:

  • mfa_required (HTTP 403) — returned when TOTP is enrolled but totp_code was not provided, or when require_mfa is enabled but the user has not yet enrolled in TOTP (the user must enroll via the browser login flow first)
  • invalid_mfa_code (HTTP 403) — returned when the provided totp_code is incorrect
  • mfa_locked (HTTP 403) — returned after five failed TOTP attempts on an account, and while its MFA cooldown is active

TOTP failures have a separate account-level counter. Correct passwords and changes of source IP do not reset it. The cooldown uses account_lockout_duration, falling back to 15 minutes when that setting is zero or negative. After the cooldown, verification starts a new budget; successful TOTP verification or an administrator unlocking the account clears the counter. Disabling password lockout does not disable this TOTP limit.

Only TOTP codes are supported in the ROPC flow. Email OTP is not available because there is no interactive session to complete the challenge. See Multi-Factor Authentication for details on MFA setup and enrollment.

  • Passkey authentication is not available — ROPC only supports username/password
  • Email OTP is not available — only TOTP codes can be used for MFA in ROPC
  • No SSO session is created — each ROPC token exchange is independent
  • Account lockout still applies — repeated failed password attempts will lock the account

When require_email_verification is enabled, unverified non-admin users cannot obtain tokens through the password grant. The endpoint returns HTTP 400 invalid_grant with Email verification is required; users must finish email verification first. The browser flow’s admin recovery exemption also applies here.