-
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.
-
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.
-
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
-
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.
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.
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.
-
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"
}
-
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 |
- ? 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>
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
- Returned via Query String
https://authserver.example.com/authorize?error=invalid_request
- Returned via POST body
HTTP/1.1 400 Bad Request
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"error": "invalid_request"
}
-
Many best practices & extensions
-
22 OAuth specifications
-
~15 draft specifications
- Minor revision started in 2020 by the OAuth working group.
- No more ROPC.
- No more Implicit Flow.
- Single-use refresh tokens.
- PKCE across the board.
- No more bearer tokens in the query string.
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)
-
Considered Public Clients by OAuth authorization servers.
-
Cannot solely trust client authentication.
-
Tokens and tokens issued to these clientscan be seen and stolen.
-
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
-
A way to link a response to an application
-
Private URI scheme
- com.pluralsight.ios:/cb
-
Claimed HTTPS scheme
-
Loopback device
-
Leak keystrokes and session cookies to the host application
-
Authorization process is then exploitable
-
Increased attach surface
-
Encourage phishing
-
Best-practice for native apps.
-
Uses the system browser.
-
Password manager integration.
-
Single Sign-On.
RFC 8552 (OAuth for native apps)
-
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.
-
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.
- Traditionally means the Implicit Flow
- 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.
-
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.
-
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.
- Well-known endpoint that describes the OpenID provider:
- UserInfo endpoint
- Return claims about the delegating user.
- Access is scoped by identity specific scopes:
- profile
- openid
-
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
- Describes the token itself:
-
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
-
-
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
-
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.
-
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
-
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.
- RFC 8693
-
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
- 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.