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.
When to use ROPC
Section titled “When to use ROPC”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
How it works
Section titled “How it works”The ROPC flow is straightforward but exposes credentials:
- User provides credentials to the application (username and password)
- Application sends credentials to the authorization server’s
/auth/tokenendpoint withgrant_type=password, along with the username and password - Auth server validates credentials and returns tokens (access token, refresh token, and ID token if
openidscope is included) - Application uses tokens to access protected resources on behalf of the user
Security considerations
Section titled “Security considerations”Credential exposure
Section titled “Credential exposure”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
No multi-factor authentication
Section titled “No multi-factor authentication”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."}No consent flow
Section titled “No consent flow”ROPC bypasses the normal consent screen. The user providing their credentials is treated as implicit consent to the requested scopes.
Token request
Section titled “Token request”Make a POST request to the token endpoint with the user’s credentials.
Request parameters
Section titled “Request parameters”| Parameter | Required | Description |
|---|---|---|
grant_type | Yes | Must be password |
username | Yes | The user’s email address |
password | Yes | The user’s password |
client_id | Yes | Your client identifier |
client_secret | Conditional | Required for confidential clients |
scope | No | Space-separated list of scopes (defaults to openid if not provided) |
Example requests
Section titled “Example requests”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"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-backend-app" \ -d "client_secret=my-secret" \ -d "password=userpassword" \ -d "scope=openid profile offline_access"curl -X POST https://auth.example.com/auth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -u "my-backend-app:my-secret" \ -d "grant_type=password" \ -d "password=userpassword" \ -d "scope=openid profile offline_access"Token response
Section titled “Token response”{ "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
openidscope is included - The
scopein the response confirms which scopes were granted
Supported scopes
Section titled “Supported scopes”ROPC supports both OpenID Connect scopes and resource:permission scopes:
OpenID Connect scopes
Section titled “OpenID Connect scopes”| Scope | Description |
|---|---|
openid | Required for ID token. Default if no scope provided |
profile | User profile claims (name, nickname, etc.) |
email | User’s email and email_verified claims |
address | User’s address claims |
phone | User’s phone number claims |
groups | User’s group memberships |
attributes | Custom user attributes |
Resource permissions
Section titled “Resource permissions”You can also request resource:permission scopes:
scope=openid product-api:read product-api:writeRefreshing tokens
Section titled “Refreshing tokens”ROPC always returns a refresh token. Use it to obtain new tokens without re-prompting for credentials:
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..."Configuration
Section titled “Configuration”Enabling ROPC
Section titled “Enabling ROPC”By default, ROPC is disabled for security reasons. To enable it:
Global setting
Section titled “Global setting”- Navigate to Settings → General in the admin console
- Enable “Resource Owner Password Credentials flow”
- Save changes
This enables ROPC for all clients that inherit from the global setting.
Per-client setting
Section titled “Per-client setting”Individual clients can override the global setting:
- Navigate to Clients → [Client Name] → OAuth2 flows in the admin console
- 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
- Save changes
Client configuration
Section titled “Client configuration”ROPC can be used with both public and confidential clients:
| Client Type | Client Secret | Use Case |
|---|---|---|
| Public | Not required | Mobile apps, desktop apps, CLI tools |
| Confidential | Required | Backend services acting on behalf of users |
Error handling
Section titled “Error handling”Error responses follow RFC 6749 Section 5.2 and include cache prevention headers:
Cache-Control: no-storePragma: no-cacheCommon errors
Section titled “Common errors”| Error | HTTP Status | Description |
|---|---|---|
invalid_grant | 400 | Invalid username/password, user disabled, or 2FA enabled |
invalid_client | 401 | Client authentication failed (wrong secret) |
invalid_request | 400 | Missing required parameter (username, password) |
unauthorized_client | 400 | Client not authorized for ROPC grant |
invalid_scope | 400 | Requested scope invalid or user lacks permission |
For invalid_client errors, a WWW-Authenticate: Basic header is included when HTTP Basic authentication was used.
Example error responses
Section titled “Example error responses”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'."}Migration to authorization code flow
Section titled “Migration to authorization code flow”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
Best practices
Section titled “Best practices”If you must use ROPC:
- Use HTTPS only - Never transmit credentials over unencrypted connections
- Don’t store passwords - Exchange credentials immediately, don’t persist them
- Use short token lifetimes - Minimize exposure window if tokens are compromised
- Request minimal scopes - Only request what your application needs
- Monitor for abuse - Log authentication attempts and watch for anomalies
- Enable rate limiting - Protect against credential stuffing attacks
- Plan for migration - Treat ROPC as temporary while planning for better flows
- Educate users - Warn users about entering credentials in the application
Token validation
Section titled “Token validation”When your API receives tokens from ROPC:
- Verify the signature using the authorization server’s public keys (JWKS endpoint)
- Check the issuer (
iss) matches your authorization server - Check expiration (
exp) to ensure the token hasn’t expired - Validate scopes to ensure the token has the required permissions
- Verify the audience (
aud) if your API is a specific resource
See the Tokens documentation for more details on token validation.