General Information

Overview

  • An delegation framework (also used as an authentication framework) that enables web applications to request limited access to a user's account on another application without exposing their credentials to the requesting application.

  • There are defined interactions among 3 distinct parties:

    1. Client application: the application that wants to access the user's data.

    2. Resource owner: the user whose data is requested to be shared.

    3. OAuth service provider: The application that controls the user's data. It supports OAuth via an API that both the authorization server and the resource server uses.

  • OAuth implementations are known as flows or grant types (the focus will be on the authorization code and implicit grant types).

Grant Types

Determines the OAuth process and how the access token is sent.

OAuth Scopes

The client app must specify which data wants to access and what it wants to do with it via the scope parameter of the authorization request. The scope is an arbitratry string, so its format varies.

# Scope examples for reading a user's contact list
scope=contacts
scope=contacts.read
scope=contact-list-r
scope=https://oauth-authorization-server.com/auth/scopes/user/contacts.readonly

When OAuth is used for authentication, the standardized OpenID Connect scopes are often used.

Authorization Code Flow

  1. The client send request access via the /authorization endpoint. Although the endpoint name can vary, the request parameters are indicative of this step.

    • client_id -> mandatory parameter, the unique ID of the client app.

    • redirect_uri -> aka callback URI.

    • response_type -> which flow the client app wants to initiate.

    • scope -> subset of user's data needed.

    • state -> a combination of a session and CSRF token.

GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=code&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: oauth-authorization-server.com
  1. The authorization server receives the request, redirects the user to a login page for consent.

  2. The user is then redirected to the client's /callback which will contain the authorization code.

GET /callback?code=a1b2c3d4e5f6g7h8&state=ae13d489bd00e3c24 HTTP/1.1
Host: client-app.com
  1. Next, the authorization code is exchanged with an access token via a server-to-server POST request from the client to /token. All the communication from this point on takes place in a secure back-channel.

    • client_secret -> the client authenticates itself by including the key that it was assigned when registering with the OAuth service.

    • grant_type -> which flow the client app wants to use.

POST /token HTTP/1.1
Host: oauth-authorization-server.com

client_id=12345&client_secret=SECRET&redirect_uri=https://client-app.com/callback&grant_type=authorization_code&code=a1b2c3d4e5f6g7h8
  1. The OAuth service validates the token request and grants the client app an access token with the requested scope.

{
    "access_token": "z0y9x8w7v6u5",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "openid profile",

}
  1. The client app makes an API call to /userinfo and submits the access token via the Authorization: Bearer header.

GET /userinfo HTTP/1.1
Host: oauth-resource-server.com
Authorization: Bearer z0y9x8w7v6u5
  1. The resource server verifies the token and responds with the data requested.

Implicit Grant Type

The main difference with the Authorization Code flow is that the authorization code part is skipped and the client app receives the access token right after the user gives their consent.

  1. In the authorization request the response_type is set to token instead of code.

GET /authorization?client_id=12345&redirect_uri=https://client-app.com/callback&response_type=token&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: oauth-authorization-server.com
  1. User gives consent.

  2. Instead of sending the code, it will send the access token.

GET /callback#access_token=z0y9x8w7v6u5&token_type=Bearer&expires_in=5000&scope=openid%20profile&state=ae13d489bd00e3c24 HTTP/1.1
Host: client-app.com
  1. The client app uses the token to request the /userinfo endpoint.

  2. The resource server validates the token and responses with the data requested.

Image taken from here.

OAuth for Authentication

  • OAuth specs are vague and the vast majority of the implementation is optional which presents many opportunities for bad practice.

  • When used for authentication the basic flow remains the same; the difference is how the client app uses the receiving data. For the end-user the result is like a SAML-based SSO.

    1. User chooses a social media account to log into the client app.

    2. The client app uses the social media's OAuth service to request access to data that it can use to identify the user.

    3. The client app receives an access token and requests this ID data from the resource server from /userinfo.

    4. The client app uses this data in place of creds to log the user in. The access token received from the AS is often used instead of a traditional password.

Identifying OAuth Authentication

  • Option to log in using your account from another website -> OAuth.

  • Intercept the above request and see if it matches the authorization request which includes standard parameters, such as client_id, redirect_url, and response_type.

  • Identify the OAuth provider from the hostname; this is a public API and detailed documentation might be available -> endpoints and configuration options.

  • Try sending GET requests to standard endpoints, such as /.well-known/oauth-authorization-server and /.well-known/openid-configuration. These will often return a JSON config file containing key info.

Last updated