Skip to content

Instantly share code, notes, and snippets.

@rbento
Last active November 19, 2021 08:00
Show Gist options
  • Save rbento/5a006c75d28ab93c1a1ee1f901e1a727 to your computer and use it in GitHub Desktop.
Save rbento/5a006c75d28ab93c1a1ee1f901e1a727 to your computer and use it in GitHub Desktop.

OAuth 2.0 Authorization Framework

  • https://oauth.net/2.1/

  • Authorization Framework.

  • Specifically Built for HTTP APIs.

  • Scoped API access.

  • A delegation protocol.

  • Is not authentication.

  • It does not give the client application any sort of indication of who the user is and how they authenticated.

  • OAuth and its extensions are the go-to standard for API authorization.

Players

  • Protected Resource (HTTP API)

  • Client (Requesting Application)

    • The application wanting to access the protected resource in someone's behalf.
  • Resource Owner (The user)

    • The user owning the protected resource.
    • In OAuth the data on the API belongs to the user, not the API.
    • The user needs to consent on access to its data.
  • Authorization Server

    • Handles authorization requests.
    • Trusted by all parties involved.

Implicit Grant Type

  • Designed for "public clients"

  • Best for clients accessing resources directly from the browser

  • Client application does not have a server (Served from CDN)

  • Client application cannot be preloaded with a secret

  • No explicit client authentication

  • Less secure than the Authorization Code Grant Type

  • Client applicatiojn cannot keep a secret, so it is there is no point receiving an authorization code, so a token is asked/received directly. (response_type=token)

  • Registered Redirect URIs are the main defense against uanuthorized applications requesting tokens, so it is important that it matches.

  • Token is received in the URL fragments

Security Concerns

  • Access Tokens are exposed to the resource owner, via URL and can be stored in the browser storage.

  • Any JavaScript code can access it.

  • No validation that access tokens are intended for a given client. Another token may be injected.

Authorization Request

https://authserver.example.com/authorize ?response_type=token &client_id=8sd933h4 &redirect_uri=https://client.example.com/callback &state=xyz &scope=api1 api2.read

Same-Origin Security Policy

  • Implemented within browsers to prevent requests to a different domain.

  • This would prevent Authorization Requests to be sent to a server hosted in another domain.

CORS - Cross-Origin Resource Sharing

  • Since the release of OAuth 2.0

  • Allows the authorization server to maintain a whitelist of permitted origins, HTTP verbs and headers that are allowed to make cross-origins requests to it.

PKCE - Proof Key for Code Exchange

CORS + PKCE = No Implicit Flow. Instead utilize Authorization Code + PKCE.

Client Credentials Grant Type

What if there are no clear resource owner? Or the client application has no users involved?

  • Designed for client applications who are the resource owner.

  • Best for machine-to-machine communication.

  • This flow requires client authentication.

  • The client application sends its credentials directly to the token endpoint.

Token Request

POST /token HTTP/1.1

Host: server.example.com Content-Type: application-x-form-urlencoded Authorization: Basic 98h32149h329324h923j498j3223=

grant_type=client_credentials &scope=api1 api2.read

Token Response

HTTP/1.1 200 OK

Content-Type: application/json

{

"access_token": "2YotnFZFE09ifoojsdfjoisfAA", "token_type": "Bearer", "expires_in": 3600, "scope": "api2.read" }

Differences with API Keys/HTTP Basic Authentication

  • Not sending credentials with every request. Credentials are sent only on the token request significantly reducing the attack surface.

  • Short lived access tokens allows removing the credentials from requests and also scope the amount of time any stolen token might be used for, which contrasts with the API Key, ehich could be used for months.

ROPC - Resource Owner Password Credentials

  • Designed as a stop-gap for legacy applications

  • Negates most benefits of OAuth

  • Considered deprecated by many membersof the OAuth working group.

  • There is no way for the authorization server to tell the difference between a user and a client application.

  • Same vulnerabilities as credential sharing.

Token Request

POST /token HTTP/1.1

Host: server.example.com
Content-Type: application/x-www.form-urlencoded
Authorization: Basic cj9s8dyg9sdh7s98ys9d8h

grant_type=password
&username=johndoe
&password=039gh0
&scope=api1 api2.read

Token Response

HTTP/1.1 200 OK

Content-Type: application/json

{
	"access_token": "43uib34h934onn3940h",
	"token_type": "Bearer",
	"expires_in": 3600,
	"scope": "api2.read"
}

Refresh Token

  • Swap for new tokens

  • Allows for long-lived access

  • Highly confidential

  • User should be informed

  • Is represented by a scope, offline_access, standardized by OpenID Connect

  • User should always be prompted if the offline_access scope is present, even if previous consent was given.

  • The refresh token should never be exposed to the browser or exchanged with any other system other the authorization server.

  • Should be reusable or one-time use have a set expiry or sliding expiry based on usage.

  • One-Time Use and set expiry around 1 month is a great policy.

Authorization Request

https://authserver.example.com/authorize
?response_type=code
&client_id=983h49j34
&redirect_uri=https:client.example.com/callback
&state=xyz
&scope=api1 api2.read offline_access

Token Response

HTTP/1.1c200 OK
Content-Type: application/json

{
	"access_token": "9283bj023h08932b40j9b",
	"token_type": "Bearer",
	"expires_in": 3600,
	"refresh_token": "298g3203bj23h293ib",
	"scope": "api2.read offline_access"
}

Refresh Token Request

POST /token HTTP/1.1

Host: server.example.com
Authorization: Basic 928304igo32h4g0h
Content-Type: application/x-www-form-urlencoded

grant_tytpe=refresh_token &refresh_token=923h4b2o34 &scope=api1

Refresh Token Response

HTTP/1.1 200 OK

Content-Type: application/json

{
	"access_token": "Bearer",
	"token_type": "Bearer",
	"expires_in": 3600,
	"refresh_token": "h9283g49234932h4",
	"scope": "api2.read offline_access"
}

Who can use Refresh Tokens?

Authorization Flow Can request offline_access
Authorization Code Yes
Implicit No
Client Credentials No
ROPC Yes

Response Modes

  • ? Query String
  • # Hash Fragment
    • Preferrable over Query String
  • Form Post
    • Formalized by the OpenID specification.

Form Post HTML Example

<html>
	<head><title>Submit This Form</title></head>
	<body onload="javascript:document.forms[0].submit()">
		<form method="post" action="https://client.example.org/callback">
			<input type="hidden" name="state" value="xyz" />
			<input type="hidden" name="code" value="j9wdhf9wfedh9ewhf9b" />
		</form>
	</body>
</html>

Error Types

The Authorization and Token endpoints have a set fields and 6 values to be returned upon failure.

Fields

  • error
  • error_description
  • error_uri
  • state

Values (400)

  • invalid_request
  • invalid_client (401)
  • invalid_grant
  • unauthorized_client
  • unsupported_grant_type
  • invalid_scope
Authorization Error Response
  • Returned via Query String
    • https://authserver.example.com/authorize?error=invalid_request
Token Error Response
  • Returned via POST body
HTTP/1.1 400 Bad Request
	Content-Type: application/json
	Cache-Control: no-store
	Pragma: no-cache
	{
		"error": "invalid_request"
	}

OAuth 2.0

  • Many best practices & extensions

  • 22 OAuth specifications

  • ~15 draft specifications

OAuth 2.1

  • Minor revision started in 2020 by the OAuth working group.

OAuth 2.1 Changes

  • No more ROPC.
  • No more Implicit Flow.
  • Single-use refresh tokens.
  • PKCE across the board.
  • No more bearer tokens in the query string.

OAuth 2.1 Flows

App Type Recommnded Flow
Server-side Authorization Code + PKCE
Single-Page Applications Authorization Code + PKCE
Native App Authorization Code + PKCE
Machine-To-Machine Client Credentials

Further Reading:

  • RFC 6749 (OAuth 2.0)
  • RFC 6819 (Threat model & security considerations)

Native Applications

  • Considered Public Clients by OAuth authorization servers.

  • Cannot solely trust client authentication.

  • Tokens and tokens issued to these clientscan be seen and stolen.

PKCE Proof Key for Code Exchange
  • A simple countermeasure for ensuring stolen codes cannot be swapped for tokens.

  • So effective that its use is recommended for all client applications that use the authorization code flow.

  • RFC 7636

  • Links the authorization request to the token request using a proof key that only the original requests would have known

Redirect URI Options
  • A way to link a response to an application

  • Private URI scheme

    • com.pluralsight.ios:/cb
  • Claimed HTTPS scheme

  • Loopback device

Embedded User-Agent (Browser)
  • Leak keystrokes and session cookies to the host application

  • Authorization process is then exploitable

  • Increased attach surface

  • Encourage phishing

In-App Browser Tabs
  • Best-practice for native apps.

  • Uses the system browser.

  • Password manager integration.

  • Single Sign-On.

RFC 8552 (OAuth for native apps)

Best-Practices for Browser-based Applications

  • Code running directly in the end user's browser asopposed to a webserver.

  • Single Page Applications (SPAs)

    • Same security profile as Native Applications.
  • Considered as a Public Client as opposed to a Confidential Client.

Security Profile
  • Network calls are visible to the user

  • Easy to replay API calls.

  • No secure storage.

  • Token theft by malicious code running with the application.

    • Injected by compromised CDNs or browser plugins hijacking API calls.
OAuth Within the Browser
  • Traditionally means the Implicit Flow
SameSite Cookies
  • An alternative to OAuth for Browser-based Applications.

Limitations

  • Cannot be used with 3rd Party APIs

  • Can be an issue for many SPAs with many APIs.

  • Means that APIs must start managing user authentication & session management.

Backend for Frontend
  • A recommended approach for many APIs that are called from many browser-based applications.

  • The browser-based application using a SameSite cookie to communicate with its corresponding server-side API, hosted on the same domain.

  • The API is responsible for handling all interaction with the authorization server.

  • The API acts as a Proxy to any shared APIs or even 3rd Party APIs, taking requests from the SPA and reissuing them to the next API along with the appropriate access token.

  • This simple technique removes all tokens from the browser and keeps them safely stored in the backend. It also allows for the use of refresh tokens.

OpenID Connect

  • Identity Layer on top of OAuth 2.0.

  • Formalizes some of the OAuth ambiguities:

    • Define Token types
    • Standardizes cryptography and validation procedures.
  • Only adds to OAuth.

  • Authorization Server also acts as an Identity Provider.

  • Discovery document

    • Well-known endpoint that describes the OpenID provider:
      • URLs of endpoints.
      • Supported scopes and claim types.
      • Public keys for verifying tokens.
      • Allows client applications to automatically configure themselves to use the identity provider.

Identity Access

  • UserInfo endpoint
    • Return claims about the delegating user.
    • Access is scoped by identity specific scopes:
      • profile
      • openid
      • email

Identity Token

  • New type of token.

  • Returned as part of authorization and token requests.

  • Describes the authentication event itself.

    • Intended for the client application.
    • Client verifies the both the data within it and whether it has been tampered with.
    • The identity provider signs the token with its private key using the corresponding public key retrieved from the OpenID Connect discovery document.
  • It is always a JSON Web Token - JWT

  • Has 3 parts:

    • Header
    • Payload
    • Signature
    • Each part is delimited by a full stop.
    • Header and Payload are simply Base64 encoded.
  • Header:

    • Describes the token itself:
      • alg - algorithm used to sign the token.
      • kid - matched back to a key in the provider's discovery document.
      • typ - JWT
  • Payload

    • Provides the client application with enough data to decide whether or not it should trust the token.

      • nbf - not use before
      • exp - when the token expires
      • iat - issued at
      • auth_time - when end-user authenticated
      • iss - who issued the token
      • aud - intended audience - should the the client application's client_id
      • nonce - no more than once - similar to the state parameter sent with the authorization request - verifiable due to its digital signature
      • at_hash - a hash of all codes returned along side with the token
      • sub - subject - unique identifier for the user
      • idp - the identity provider who issued the identity
      • amr - authentication method reference - shows how the user authenticated

Hybrid Flow

  • Added by OpenID Connect

  • Interesting alternative for authorizing confidential clients

  • Allows every combination of code, token and id_token

  • Allows all other combinations of response_type

OAuth 2.0 Authorization Server Metadata

  • RFC 8414

  • Inspired by the discovery document

  • Allows to use a well known endpoint and a standardized schema to describe your authorization server.

  • Recent addition to OAuth spec.

  • Always hosted at /.well-known/authorization-server

    • Just need to know the base URL.
  • Can be loaded by an application at runtime and refresh periodically to see if there were any changes.

  • This approach allows programmatic integration with minimal manual configuration and get automatic updates.

  • This spec came out in 2018 and adoption has been very successful.

  • Offered by major authorization servers.

  • Client libraries avauilable to load and parse this metadata format.

OAuth Device Flow

  • RFC 8628

  • For browserless devices

    • Smart TVs

    • Home Assistance

    • Printers

    • Custom browsers in these devices may not be trusted.

  • For Input Constrained Devices

    • Controllers
    • Remotes
  • Users should not type 20+ passwords in all devices.

  • A secondary Device is used to authorize the main device.

Device Authorization Request

POST /device_authorization HTTP/1.1

Host: server.example.com
Content-Type: application/x-www-form-urlencoded

client_id=327486543276

Device Authorization Response

{
	"device_code": "2937t42iv3 v4h9g23h40iv23940",
	"user_code": "HEYR-IJEJ",
	"verification_uri": "https://www.example.com/device",
	"verification_uri_complete": "https://www.example.com/device?user_code=HEYR-IJEJ",
	"expires_in": 1800,
	"interval": 5
}
  • The verification_uri_complete can be used to generate a QR code to the user for convenience.

  • The interval in seconds determines how often the device polls the authorization server to verify whether the user has been authorized. These requests are as follows:

Token Request - Request

POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www.form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:device_code
&device_code=823940hn2034gh2p34j089h_guiwenriwoberowueiryhewrh820934b0
&client_id=928374927384

Token Request - Response

  • While not authorized:
{
	"error": "authorization_pending"
}
  • Once complete:
	"access_token": "098324230423074900j23",
	"token_type": "example",
	"expires_in": 3600

SAML & OAuth

  • RFC 8414

  • SAML

    • Security Assertion Markup Language

    • Popular XML-based framework

    • Allows for identity and security information to be exchanged between service providers and identity providers.

    • Does not includeany alternative to OAuth

    • Not made to protect APIs

    • There is an extension Grant Type that allows SAML assertions to be swapped for OAuth access tokens - saml2-bearer.

Token Request - Request

  • SAML assertion is Base64 encoded.
POST /token HTTP/1.1
	Host: server.example.com
	Content-Type: application/x-www-form-urlencoded

	grant_type=urn:ietf:params:oauth:grant-type:saml2-bearer
	&assertion=09324h2384h23ou4in23984h

Usual token response is then received.

Token Exchange

  • RFC 8693
API-to-API Delegation
  • Allows us to maintain the authorization model and keep resource level authorization rules within the resource itself

  • Can be used for swapping any kind of token. From generic oauth access token, JWT, SAML assertion or OpenID COnnect identity token.

Token Exchange - Request

  • The API1 authenticates itself

  • Then requests access to API2 by sending the original access token that it received from the client application

POST /token HTTP/1.1

	Host: server.example.com
	Authorization: Basic 98324uh502309h4
	Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&scope=api2
&subject_token=accVkjcJub02u4h43hj23j4234
&subject_token_type=urn:ietf:params:oauth:token-type:access_token

See also

  • UMA 2
    • Adds the concept of resource owners delegating access to other users in addition to client applications.
  • JWT Client Authentication
    • RFC 7523
    • Very effective way of removing client secrets from applications, instead authenticating client via the usage of digitally signed JWTs.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment