OAuth is an authorization protocol that enables users to grant third-party access to their web resources without sharing their passwords. OAuth is used to provide client applications (third-party applications) with “secure delegated access.” There are two versions of OAuth: OAuth 1.0a and OAuth 2.0. These specifications are different and cannot be used together: there is no backwards compatibility between them.
OAuth 2.0 Protocol Problem Statement
Example: A user has signed up on test.com, and test.com needs access to the user’s Google contacts.
Solution (High Level)
When test.com needs access to a user’s Google contacts, the user is presented with a prompt that is similar to the following prompt:
When the user selects “YES”, they are redirected to Google’s OAuth server, where they log in. The user is redirected away from the third-party application (test.com), and passwords are entered only on OAuth servers (first-party applications that we trust), so passwords are secure.
Upon successful authentication, an access token is generated by Google and sent to the test.com server. Using this token, test.com can retrieve the user’s Google contact list.
To understand OAuth better, let’s first understand the components involved.
Resource owner: The person or application that owns the data that is to be shared
Resource server: The server hosting the protected resources
Client application: The third-party application “client” is the application that is attempting to gain access to the user’s data
Authorization server: The server authorizing the client application to access the protected resources of the resource owner
Note:Everyorganization would have a custom OAuth implementation. The flow described below is based on the OAuth framework documentation and how it was intended to be used. Please analyze the implementation you encounter to identify any differences in behaviour.
Registering an Application
Note:Everyorganization would have a custom OAuth implementation. The flow described below is based on the OAuth framework documentation and how it was intended to be used. Please analyze the implementation you encounter to identify any differences in behavior. To integrate the OAuth authorization process with a new client application, the developers must first register the new application with the OAuth service. Typically, basic information such as the application name, website, and logo is used to register a new application. In addition, you must register a redirect URI to be used for redirecting users to web server, browser-based, or mobile applications.
Redirect URIs: The OAuth service will redirect users only to a registered URI, which helps prevent some attacks such as open redirection and token leakage. Any HTTP redirect URI must be served via HTTPS. This requirement helps prevent the interception of tokens during the authorization process.
Client ID and Secret
The first step of OAuth 2 is to obtain authorization from the user. This step is called the “authorization grant.” It is typically done for browser-based or mobile apps by showing an interface that is given to the user by the OAuth service.
For various use cases, OAuth 2 offers many grant forms. The defined grant types are as follows:
1. The resource owner (user) accesses the client application.
2. The client application tells the user to log in to the client application via an authorization server (e.g. Facebook, Twitter, Google).
3. To log in via the authorization server, the user is redirected to the authorization server’s login page by the client application. The client application sends its client ID in the request to the authorization server, so the authorization server knows which application is trying to access the protected resources.
response_type=code indicates that the client application expects to receive an authorization code;
client_id is the client ID that was received when the application was registered;
redirect_uri indicates the URI to return the user to after authorization is complete;
scope is one or more scope values that indicate which parts of the user’s account the client application requires access to; and
state is a random string generated by the client application, which will be verified later as a form of CSRF protection.
4 & 5. The user logs in via the authorization server. The user is then asked whether they want to grant the client application access to their resources. If the user accepts, they are redirected back to the client application.
6. When the user is redirected back to the client application (with the help of a 302 response code), the authorization server sends the user to a specific URI, which the client application has registered with the authorization server in advance.
7. In the redirection, the authorization server sends an authorization code, which represents the authorization. The following is a sample request, which is triggered by the 302 redirection response:
8. When the redirect URI in the client application is accessed, the client application server connects directly to the authorization server. The client application server sends the authorization code along with its own client ID and client secret.
9. If the authorization server can accept these values, the authorization server sends back an access token.
10. The client application server can now use the access token to request resources from the resource server.
This portion of this post explains the steps that a pentester can take while assessing OAuth implementations.
Step 1: Identify protocol version
Step 2: Identify grant type being used
Step 3: Check for misconfigurations
Identifying OAuth Protocol Version
To identify the protocol version being used, we can use the help of the authorization grant request that is travelling from the browser of the resource owner to the authorization server (refer to step 3 in Figure 3).
The first request in the authorization grant process for OAuth 1.0 would appear as follows:
OAuth 1.0 follows the three-legged flow. The three steps are as follows:
Temporary Credentials Acquisition: The client receives a set of temporary credentials from the authorization server
Authorization: The user “authorizes” the request token to access their account
Token Exchange: The client exchanges the short-lived temporary credentials for a long-lived token
OAuth 2.0 supports four flows. To identify the type, we can look at the authorization grant request that originated in step 3 (refer to Figure 3).
The value for response_type can be identified from the GET parameters. The value can be
code for the authorization code grant type or
token for the implicit grant type.
If the request does not have a response_type parameter, then look for the grant_type parameter. The value can be
password for the resource owner password credentials grant type or
client_credentials for the client credentials grant type.
Insufficient Redirect URI Validation
Authorization servers must match client-redirect URIs and pre-registered URIs. This measure helps prevent authorization codes and access tokens (depending on the grant type) from being leaked.
Clients should avoid forwarding the user to a URI obtained from a query parameter (user-controlled) because such a function could be used to exfiltrate authorization codes and access tokens. If there is a strong need for this kind of redirect, clients should implement appropriate countermeasures against open redirection.
In the authorization grant request, manipulate the REDIRECT_URI parameter and enter URIs that should not be acceptable. The goal is to trick the authorization server into sending the authorization code to an attacker-controlled website.
For instance, if the application redirects the user to https://example.com/test with the authorization code, try entering different values in the REDIRECT_URI parameter, and see whether it is accepted and whether tokens are sent to an attacker-controlled website. Test values for redirect URI can be as follows:
Check whether the authorization server returns the “auth_code” value over HTTP instead of HTTPS. If it does, then eavesdropping and access-code leakage could occur. Also, authorization codes can be leaked via the Referer header, the web server or proxy logs, an open redirect, or the browser history.
Cross-Site Request Forgery (CSRF)
Clients must prevent CSRF and ensure that each authorization response is accepted only once. One-time use CSRF tokens that are carried in the state parameter should be used for that purpose. Verify that the “state”parameter in each authorization grant request is validated by the client application.
Ensure that the authorization server does not issue long-lasting credentials. The “access_token” token should expire 30 minutes, at most, after it is issued. A refresh token should be used to fetch fresh access tokens (note that this is applicable only when the token can be used to access sensitive data).
Leaked Client Secrets
Ensure that the client applications (such as single-page applications or mobile applications) do not have hard-coded client secret strings in the source code. Client secrets can be used to impersonate client applications in order to request the authorization server to issue access tokens. They can also be used to replay refresh tokens and authorization codes.
Scope Value Manipulation
Ensure that the authorization server generates an “access_token” token for the intended scope. For instance, if test.com requires access to Google contacts, then in the authorization grant request, the value of scope would be as follows: scope = contacts
Ensure that the authorization server does not grant access tokens for other scopes such as email or photos.
The implicit grant (with the “token” response type) and other response types that cause the authorization server to issue access tokens in the authorization response are vulnerable to access-token leakage and access-token replay. Moreover, no viable mechanism exists to cryptographically bind access tokens that are issued in the authorization response to a certain client. This makes replay detection for such access tokens at resource servers impossible.
In order to avoid these issues, clients should not use the implicit grant or any other response type that causes the authorization server to issue an access token in the authorization response.
Clients should instead use the “code” response type (a.k.a. the authorization code grant type) or any other response type that causes the authorization server to issue access tokens in the token response. This approach allows the authorization server to detect replay attempts and generally reduces the attack surface because access tokens are not exposed in URLs. It also allows the authorization server to sender-constrain the issued tokens.
OAuth Security Best Practice Guidelines
Use TLS for all communication
Allow only one use per token and consider temporarily revoking access for clients that send multiple invalid tokens
Do not use OAuth 2.0 for authentication (use OpenID Connect instead)
Use the state parameter to prevent CSRF attacks
Reduce the scope of tokens to the minimum required access
Switch to the authorization code type from the implicit type and use PKCE
Implement short-lived and one-time-use authorization codes
Send the access token in the response body. CORS can be used to send a cross-domain POST request to share the token.
Defend your front-end applications from XSS attacks that could steal tokens from localStorage
Watch out for the open-redirection vulnerabilities