Home  >  Research  >  OAuth 2.0 Security Author…

OAuth 2.0 Security Authorization Framework

Written By: Karan Kapoor

What Is OAuth 2.0?

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.

Figure 1: OAuth roles

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:

Figure 2: Sample authorization grant pop-up

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.

OAuth Roles

  • 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: Every organization 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: Every organization 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

After registering the client application, the developers receive a client ID and, optionally, a client secret. The client ID is considered public information and is used to create login URLs or is included on a page in the client application in the JavaScript source code. The client secret must be kept confidential. If a deployed application, such as single-page JavaScript apps or native apps, cannot keep the secret confidential, then the secret is not used and, ideally, the OAuth service should not first issue a secret to these types of apps.

Authorization

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:

  • Authorization code: For apps running on a web server, browser-based and mobile apps
  • Resource owner password credentials: For logging in with a username and password (only for first-party apps)
  • Client credentials: For application access without a user being present
  • Implicit: Previously recommended for clients without a secret but has been superseded by using the Authorization code grant with PKCE.

The most used grant type is the authorization code grant. We will be discussing this flow in detail.

Authorization Code Grant

An authorization grant that uses an authorization code works as described in the following flow chart, with the steps explained below:

Figure 3: Authorization code grant flow

Image source: https://developer.okta.com/blog/2019/08/22/okta-authjs-pkce

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.

  • Sample request: https://authorization-server.com/auth?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=1234zyx

In this request,

  • 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:

  • Sample request: https://client-app.com/cb?code=AUTH_CODE_HERE&state=1234zyx

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.

  • Sample request:

POST https://authorization-server.com/token

.

.

grant_type=authorization_code&code=AUTH_CODE_HERE&redirect_uri=REDIRECT_URI&client_id=CLIENT_ID&client_secret=CLIENT_SECRET

  • Sample response:

{

  "access_token”: "...",

  "token_type": "...",

  "expires_in": "...",

  "refresh_token": "...",

}

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.

Testing Guide

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:

POST /oauth1/request HTTP/1.1
Host: server.example.com
Authorization: OAuth realm="Example",
               oauth_consumer_key="jd83jd92dhsh93js",
           	oauth_signature_method="HMAC-SHA1",
               oauth_timestamp="123456789",
               oauth_nonce="7d8f3e4a",
               oauth_callback="http%3A%2F%2Fclient.example.com%2Fcb",
           	oauth_signature="..."

The first request in the authorization grant process for OAuth 2.0 would appear as follows:

https://authorization-server.com/auth?response_type=code&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=photos&state=1234zyx

Identifying Grant Type

OAuth 1.0 follows the three-legged flow. The three steps are as follows:

  1. Temporary Credentials Acquisition: The client receives a set of temporary credentials from the authorization server
  2. Authorization: The user “authorizes” the request token to access their account
  3. 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.

Common Misconfigurations

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:

Token Leakage

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.

Long-Lasting Credentials

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.

Implicit Grant

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

Sources

OAuth 2.0

OAuth 1.0

Further Reading on Attack Scenarios

Advisory Labs

Stay Up To Date

Get the latest cybersecurity news and updates delivered straight to your inbox.
Sign up today.