OAuth 2.0 Simplified

Portland Linux/Unix Group - December 7, 2017

OAuth 2.0 Simplified



Portland Linux/Unix Group - December 7, 2017

aaronpk.com

@aaronpk

Twitter Clients (2012)

Obvious problems...

What is OAuth?

OAuth is a framework for users to
authorize
applications to act on their behalf

Roles

Access Token

Obtaining an Access Token

Applications use an OAuth flow to obtain an access token

Using a Bearer Token

POST /resource/1/update HTTP/1.1
Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia
Host: api.authorization-server.com

description=Hello+World

Registering an Application

Registering an Application

Registering an application gives you a client_id and if the application is not a "public client", then also a client_secret.

These identify the application to the service.

Client ID and Secret

A "public client" means anything where the client cannot keep strings confidential.

No secret is used for these clients, only the ID

Web-Based Apps

Build the "Log in" link

Build the "Log in" link

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

If Allowed

The user is redirected back to the application with an authorization code

https://example.com/auth?code=AUTH_CODE_HERE&state=1234zyx

Verify State

The application verifies the state matches the expected value, (or extracts session data from the state).

Obtaining an Access Token

Obtaining an Access Token

The application exchanges the authorization code for an access token.

POST https://api.authorization-server.com/token
  grant_type=authorization_code&
  code=AUTH_CODE_HERE&
  redirect_uri=REDIRECT_URI&
  client_id=CLIENT_ID&
  client_secret=CLIENT_SECRET

Obtaining an Access Token

The server replies with an access token and expiration time

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600,
  "refresh_token":"64d049f8b2119a5aa51e12522d5dd96d5641af5e8"
}

or if there was an error:

{
  "error":"invalid_request"
}

Single-Page Apps

Build the "Log in" link

Build the "Log in" link

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

If Allowed

The user is redirected back to the application with an authorization code

https://example.com/auth?code=AUTH_CODE_HERE&state=1234zyx

Verify State

The application verifies the state matches the expected value, (or extracts session data from the state).

Obtaining an Access Token

The application exchanges the authorization code for an access token.

POST https://api.authorization-server.com/token
  grant_type=authorization_code&
  code=AUTH_CODE_HERE&
  redirect_uri=REDIRECT_URI&
  client_id=CLIENT_ID

No client_secret is used!

Obtaining an Access Token

The server replies with an access token and expiration time

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600
}

or if there was an error:

{
  "error":"invalid_request"
}

Mobile/Native Apps

also cannot use a client_secret!

Build the "Log in" link

Redirect URIs for Native Apps

⚠️

Redirect URIs for Native Apps

There is no built-in security for redirect URIs like when we use DNS, since any app can claim any URL scheme.

So instead, we add an extra step at the beginning to solve this:

PKCE: Proof-Key for Code Exchange

RFC 7636: Implemented by Google and a few others

Build the "Log in" link

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

And open this in a native browser, not an embedded browser!

If Allowed

The user is redirected back to the application with an authorization code

fb000000://auth?code=AUTH_CODE_HERE&state=1234zyx

Verify State

The application verifies the state matches the expected value, (or extracts session data from the state).

Obtaining an Access Token

Obtaining an Access Token

The application exchanges the authorization code for an access token.

POST https://api.authorization-server.com/token
  grant_type=authorization_code&
  code=AUTH_CODE_HERE&
  redirect_uri=REDIRECT_URI&
  client_id=CLIENT_ID&
  code_verifier=VERIFIER_STRING

No client_secret is used, we use the code_verifier instead!

Obtaining an Access Token

The server compares the code_verifier with the code_challenge that was in the request when it generated the authorization code, and responds with an access token.

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600,
  "refresh_token":"64d049f8b2119a5aa51e12522d5dd96d5641af5e8"
}

Refresh Tokens

Refresh Tokens

If/when your access token expires, you'll need a new one.

You probably got a refresh token when you got the access token response (single-page apps usually don't though).

Refresh Tokens

POST https://api.authorization-server.com/token
  grant_type=refresh_token&
  refresh_token=REFRESH_TOKEN_HERE&
  client_id=CLIENT_ID&
  client_secret=CLIENT_SECRET

Refresh Tokens

The server replies with a new access token

{
  "access_token":"RsT5OjbzRn430zqMLgV3Ia",
  "expires_in":3600,
  "refresh_token":"64d049f8b2119a5aa51e12522d5dd96d5641af5e8"
}

Further Reading

Thanks!

oauth.net
the spec, links to libraries, etc

oauth2simplified.com
my book!

aaronpk.com @aaronpk