Skip to content

Resource Owner Password Credentials Flow

The Resource Owner Password Credentials (ROPC) flow allows applications to directly exchange a user’s username and password for tokens. It’s defined in RFC 6749 Section 4.3.

The ROPC flow should only be considered for:

  • Legacy applications that cannot be updated to use redirect-based flows
  • Highly trusted first-party applications where the user trusts the app with their credentials
  • Migration scenarios when transitioning from legacy authentication systems
  • Automated testing where redirect-based flows are impractical

The ROPC flow is straightforward but exposes credentials:

  1. User provides credentials to the application (username and password)
  2. Application sends credentials to the authorization server’s /auth/token endpoint with grant_type=password, along with the username and password
  3. Auth server validates credentials and returns tokens (access token, refresh token, and ID token if openid scope is included)
  4. Application uses tokens to access protected resources on behalf of the user

The application receives and transmits the user’s actual password. This means:

  • The application could store or misuse credentials
  • Credentials are transmitted over the network (always use HTTPS)
  • Password theft becomes easier if the application is compromised

If a user has 2FA enabled on their account, the ROPC request will fail with:

{
"error": "invalid_grant",
"error_description": "Resource owner password credentials grant is not available for accounts with two-factor authentication enabled. Please use the authorization code flow instead."
}

ROPC bypasses the normal consent screen. The user providing their credentials is treated as implicit consent to the requested scopes.

Make a POST request to the token endpoint with the user’s credentials.

ParameterRequiredDescription
grant_typeYesMust be password
usernameYesThe user’s email address
passwordYesThe user’s password
client_idYesYour client identifier
client_secretConditionalRequired for confidential clients
scopeNoSpace-separated list of scopes (defaults to openid if not provided)
Terminal window
curl -X POST https://auth.example.com/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "client_id=my-legacy-app" \
-d "password=userpassword" \
-d "scope=openid profile email"
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"scope": "openid profile email"
}

Key differences from other flows:

  • Refresh tokens are always issued (always as “offline” type since ROPC has no browser session)
  • ID tokens are issued when openid scope is included
  • The scope in the response confirms which scopes were granted

ROPC supports both OpenID Connect scopes and resource:permission scopes:

ScopeDescription
openidRequired for ID token. Default if no scope provided
profileUser profile claims (name, nickname, etc.)
emailUser’s email and email_verified claims
addressUser’s address claims
phoneUser’s phone number claims
groupsUser’s group memberships
attributesCustom user attributes

You can also request resource:permission scopes:

scope=openid product-api:read product-api:write

ROPC always returns a refresh token. Use it to obtain new tokens without re-prompting for credentials:

Terminal window
curl -X POST https://auth.example.com/auth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "client_id=my-legacy-app" \
-d "refresh_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."

By default, ROPC is disabled for security reasons. To enable it:

  1. Navigate to Settings → General in the admin console
  2. Enable “Resource Owner Password Credentials flow”
  3. Save changes

This enables ROPC for all clients that inherit from the global setting.

Individual clients can override the global setting:

  1. Navigate to Clients → [Client Name] → OAuth2 flows in the admin console
  2. Under “Resource Owner Password Credentials flow”, choose:
    • Inherit from global setting - Uses the global configuration
    • Enabled - This client can use ROPC regardless of global setting
    • Disabled - This client cannot use ROPC regardless of global setting
  3. Save changes

ROPC can be used with both public and confidential clients:

Client TypeClient SecretUse Case
PublicNot requiredMobile apps, desktop apps, CLI tools
ConfidentialRequiredBackend services acting on behalf of users

Error responses follow RFC 6749 Section 5.2 and include cache prevention headers:

Cache-Control: no-store
Pragma: no-cache
ErrorHTTP StatusDescription
invalid_grant400Invalid username/password, user disabled, or 2FA enabled
invalid_client401Client authentication failed (wrong secret)
invalid_request400Missing required parameter (username, password)
unauthorized_client400Client not authorized for ROPC grant
invalid_scope400Requested scope invalid or user lacks permission

For invalid_client errors, a WWW-Authenticate: Basic header is included when HTTP Basic authentication was used.

Invalid credentials:

{
"error": "invalid_grant",
"error_description": "Invalid resource owner credentials."
}

User with 2FA:

{
"error": "invalid_grant",
"error_description": "Resource owner password credentials grant is not available for accounts with two-factor authentication enabled. Please use the authorization code flow instead."
}

ROPC not enabled:

{
"error": "unauthorized_client",
"error_description": "The client is not authorized to use the resource owner password credentials grant type. To enable it, go to the client's settings in the admin console under 'OAuth2 flows', or enable it globally in 'Settings > General'."
}

User lacks permission:

{
"error": "invalid_scope",
"error_description": "The user does not have permission for scope 'product-api:write'."
}

If you’re currently using ROPC, plan to migrate to authorization code flow with PKCE.

The authorization code flow with PKCE provides:

  • No credential exposure to the application
  • Support for multi-factor authentication
  • Better security against credential theft
  • Compliance with OAuth 2.1

If you must use ROPC:

  1. Use HTTPS only - Never transmit credentials over unencrypted connections
  2. Don’t store passwords - Exchange credentials immediately, don’t persist them
  3. Use short token lifetimes - Minimize exposure window if tokens are compromised
  4. Request minimal scopes - Only request what your application needs
  5. Monitor for abuse - Log authentication attempts and watch for anomalies
  6. Enable rate limiting - Protect against credential stuffing attacks
  7. Plan for migration - Treat ROPC as temporary while planning for better flows
  8. Educate users - Warn users about entering credentials in the application

When your API receives tokens from ROPC:

  1. Verify the signature using the authorization server’s public keys (JWKS endpoint)
  2. Check the issuer (iss) matches your authorization server
  3. Check expiration (exp) to ensure the token hasn’t expired
  4. Validate scopes to ensure the token has the required permissions
  5. Verify the audience (aud) if your API is a specific resource

See the Tokens documentation for more details on token validation.