the state of oauth2
DESCRIPTION
Slides from my talk at State of the Auth in PortlandTRANSCRIPT
The State of OAuth 2Aaron Parecki • @aaronpk • aaronparecki.comState of the Auth • January 2013
aaron.pk/oauth2
Before OAuthApps stored the user’s password
Apps got complete access to a user’s account
Users couldn’t revoke access to an app except by changing their password
Compromised apps exposed the user’s password
@aaronpk
aaron.pk/oauth2
Before OAuthServices recognized the problems with
password authentication
Many services implemented things similar to OAuth 1.0
Each implementation was slightly different, certainly not compatible with each other
@aaronpk
aaron.pk/oauth2
Before OAuth 1.0Flickr: “FlickrAuth” frobs and tokens
Google: “AuthSub”
Facebook: requests signed with MD5 hashes
Yahoo: BBAuth (“Browser-Based Auth”)
@aaronpk
Some Current Implementers
The OAuth 2 Spechttp://oauth.net/2/
aaron.pk/oauth2
Definitions
Resource Owner: The User
Resource Server: The API
Authorization Server: Often the same as the API server
Client: The Third-Party Application
@aaronpk
aaron.pk/oauth2
Use CasesWeb-server apps
Browser-based apps
Username/password access
Application access
Mobile apps
@aaronpk
aaron.pk/oauth2
Use Cases – Grant TypesWeb-server apps – authorization_code
Browser-based apps – implicit
Username/password access – password
Application access – client_credentials
Mobile apps – implicit
@aaronpk
aaron.pk/oauth2
Web Server AppsAuthorization Code Grant
@aaronpk
aaron.pk/oauth2
Create a “Log In” link
Link to:
https://facebook.com/dialog/oauth?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email
@aaronpk
aaron.pk/oauth2
Create a “Log In” link
Link to:
https://facebook.com/dialog/oauth?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email
@aaronpk
aaron.pk/oauth2
Create a “Log In” link
Link to:
https://facebook.com/dialog/oauth?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email
@aaronpk
aaron.pk/oauth2
Create a “Log In” link
Link to:
https://facebook.com/dialog/oauth?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email
@aaronpk
aaron.pk/oauth2
Create a “Log In” link
Link to:
https://facebook.com/dialog/oauth?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email
@aaronpk
aaron.pk/oauth2
User visits the authorization page
https://facebook.com/dialog/oauth?response_type=code&client_id=28653682475872&redirect_uri=everydaycity.com&scope=email
@aaronpk
aaron.pk/oauth2
On success, user is redirected back to your site with auth code
https://example.com/auth?code=AUTH_CODE_HERE
On error, user is redirected back to your site with error code
https://example.com/auth?error=access_denied
@aaronpk
aaron.pk/oauth2
Server exchanges auth code for an access token
Your server makes the following request
POST https://graph.facebook.com/oauth/access_token
Post Body: grant_type=authorization_code&code=CODE_FROM_QUERY_STRING&redirect_uri=REDIRECT_URI &client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET
@aaronpk
aaron.pk/oauth2
Server exchanges auth code for an access token
Your server gets a response like the following
{ "access_token":"RsT5OjbzRn430zqMLgV3Ia", "token_type":"bearer", "expires_in":3600, "refresh_token":"e1qoXg7Ik2RRua48lXIV" }
or if there was an error
{ "error":"invalid_request"}
@aaronpk
aaron.pk/oauth2
Browser-Based Apps
Implicit Grant
@aaronpk
aaron.pk/oauth2
Create a “Log In” link
Link to:
https://facebook.com/dialog/oauth?response_type=token&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&scope=email
@aaronpk
aaron.pk/oauth2
User visits the authorization page
https://facebook.com/dialog/oauth?response_type=token&client_id=2865368247587&redirect_uri=everydaycity.com&scope=email
@aaronpk
aaron.pk/oauth2
On success, user is redirected back to your site with the access token in the fragment
https://example.com/auth#token=ACCESS_TOKEN
On error, user is redirected back to your site with error code
https://example.com/auth#error=access_denied
@aaronpk
aaron.pk/oauth2
Browser-Based Apps
Use the “Implicit” grant type
No server-side code needed
Client secret not used
Browser makes API requests directly
@aaronpk
aaron.pk/oauth2
Username/Password
Password Grant
@aaronpk
aaron.pk/oauth2
Password Grant
Password grant is only appropriate for trusted clients, most likely first-party apps only.
If you build your own website as a client of your API, then this is a great way to handle logging in.
@aaronpk
aaron.pk/oauth2
Password Grant Type
Only appropriate for your service’s website or your service’s mobile apps.
aaron.pk/oauth2
Password Grant
POST https://api.example.com/oauth/token
Post Body: grant_type=password&username=USERNAME&password=PASSWORD&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET
Response:
{ "access_token":"RsT5OjbzRn430zqMLgV3Ia", "token_type":"bearer", "expires_in":3600, "refresh_token":"e1qoXg7Ik2RRua48lXIV" }
@aaronpk
aaron.pk/oauth2
Password Grant
User exchanges username and password for a token
No server-side code needed
Client secret only used from confidential clients (Don’t send client secret from a mobile app!)
Useful for developing a first-party login system
@aaronpk
aaron.pk/oauth2
Application AccessClient Credentials Grant
@aaronpk
aaron.pk/oauth2
Client Credentials Grant
POST https://api.example.com/1/oauth/token
Post Body: grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET
Response:
{ "access_token":"RsT5OjbzRn430zqMLgV3Ia", "token_type":"bearer", "expires_in":3600, "refresh_token":"e1qoXg7Ik2RRua48lXIV" }
@aaronpk
aaron.pk/oauth2
Grant Type Summaryauthorization_code:
Web-server apps
implicit: Mobile and browser-based apps
password: Username/password access
client_credentials: Application access
@aaronpk
aaron.pk/oauth2
Grant Types & Response Typesauthorization_code:
response_type=code
implicit: response_type=token
@aaronpk
aaron.pk/oauth2
Grant Type Review
@aaronpk
aaron.pk/oauth2
Authorization CodeUser visits auth page
response_type=code
User is redirected to your site with auth code http://example.com/?code=xxxxxxx
Your server exchanges auth code for access tokenPOST /tokencode=xxxxxxx&grant_type=authorization_code
@aaronpk
aaron.pk/oauth2
ImplicitUser visits auth page
response_type=token
User is redirected to your site with access token http://example.com/#token=xxxxxxx
Token is only available to the browser since it’s in the fragment
@aaronpk
aaron.pk/oauth2
PasswordYour server exchanges username/password for access token
POST /tokenusername=xxxxxxx&password=yyyyyyy&grant_type=password
@aaronpk
aaron.pk/oauth2
Client CredentialsYour server exchanges client ID/secret for access token
POST /tokenclient_id=xxxxxxx&client_secret=yyyyyyy&grant_type=client_credentials
@aaronpk
aaron.pk/oauth2
Mobile AppsImplicit Grant
@aaronpk
aaron.pk/oauth2 @aaronpk
aaron.pk/oauth2 @aaronpk
aaron.pk/oauth2
Redirect back to your app
fb2865://authorize/#access_token=BAAEEmo2nocQBAFFOeRTd
@aaronpk
Facebook app redirects back to your app using a custom URI scheme.
Access token is included in the redirect, just like browser-based apps.
aaron.pk/oauth2 @aaronpk
aaron.pk/oauth2
Mobile Applications
Use the “Implicit” grant type
No server-side code needed
Client secret not used
Mobile app makes API requests directly
@aaronpk
aaron.pk/oauth2
Mobile ApplicationsExternal user agents are best
Use the service’s primary app for authentication, like Facebook – provides a superior user experience
Or open native Safari on iPhone, still better than using an embedded browser
Auth code or implicit grant type In both cases, the client secret should never be
used, since it is possible to decompile the app which would reveal the secret
@aaronpk
aaron.pk/oauth2
Accessing ResourcesSo you have an access token.
Now what?
@aaronpk
aaron.pk/oauth2
Use the access token to make requests
Now you can make requests using the access token.
GET https://api.example.com/me Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia
Access token can be in an HTTP header or a query string parameter
https://api.example.com/me?access_token=RsT5OjbzRn430zqMLgV3Ia
@aaronpk
aaron.pk/oauth2
Eventually the access token may expire
When you make a request with an expired token, you will get this response
{ "error":"expired_token"}
Now you need to get a new access token!
@aaronpk
aaron.pk/oauth2
Get a new access token using a refresh tokenYour server makes the following request
POST https://api.example.com/oauth/token
grant_type=refresh_token&reresh_token=e1qoXg7Ik2RRua48lXIV&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET
Your server gets a similar response as the original call to oauth/token with new tokens.
{ "access_token":"RsT5OjbzRn430zqMLgV3Ia", "expires_in":3600, "refresh_token":"e1qoXg7Ik2RRua48lXIV" }
@aaronpk
aaron.pk/oauth2
ScopeLimiting access to resouces
@aaronpk
aaron.pk/oauth2
Limiting Access to Third Parties
@aaronpk
aaron.pk/oauth2
Limiting Access to Third Parties
@aaronpk
aaron.pk/oauth2
Limiting Access to Third Parties
@aaronpk
aaron.pk/oauth2
OAuth 2 scopeCreated to limit access to the third party.
The scope of the access request expressed as a list of space-delimited strings. In practice, many people use comma-separators instead.
The spec does not define any values, it’s left up to the implementor.
If the value contains multiple strings, their order does not matter, and each string adds an additional access range to the requested scope.
@aaronpk
aaron.pk/oauth2
OAuth 2 scope on Facebookhttps://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream
@aaronpk
aaron.pk/oauth2
OAuth 2 scope on Facebook
@aaronpk
aaron.pk/oauth2
OAuth 2 scope on Githubhttps://github.com/login/oauth/authorize? client_id=...&scope=user,public_repo
@aaronpk
user
• Read/write access to profile info only.
public_repo
• Read/write access to public repos and organizations.
repo
• Read/write access to public and private repos and organizations.
delete_repo
• Delete access to adminable repositories.
gist
• write access to gists.
aaron.pk/oauth2
OAuth 2 scopeThe challenge is displaying this to the user succinctly in a way
they will actually understand
If you over-complicate it for users, they will just click “ok” until the app works, and ignore any warnings
Read vs write is a good start for basic services
@aaronpk
aaron.pk/oauth2
So what’s wrong?
@aaronpk
aaron.pk/oauth2
What I just described is one possible
implementation of an OAuth 2 server
@aaronpk
aaron.pk/oauth2
IndecisionNo required token type
No agreement on the goals of an HMAC-enabled token type
No requirement to implement token expiration
No guidance on token string size, or any value for that matter
No strict requirement for registration
Loose client type definition
@aaronpk
Indecision (continued)Lack of clear client security properties
No required grant types
No guidance on the suitability or applicability of grant types
No useful support for native applications (but lots of lip service)
No required client authentication method
No limits on extensions
@aaronpkaaron.pk/oauth2 Source: http://hueniverse.com/2012/07/oauth-2-0-and-the-road-to-hell/
aaron.pk/oauth2
The result: the OAuth RFC is a
framework, not a protocol
@aaronpk
aaron.pk/oauth2 @aaronpk
aaron.pk/oauth2 @aaronpk
OAuth 2 ServersImplementing an OAuth 2
Server
@aaronpkaaron.pk/oauth2
Implementing an OAuth 2 Server
aaron.pk/oauth2
Implementing an OAuth 2 ServerFind a server library already written:
A short list available here: http://oauth.net/2/
Read the OAuth spec in its entirety
Study other implementations like Google
Make decisions based on the security requirements of your application. In many cases the spec says SHOULD and leaves the choice up to the implementer.
Understand the security implications of the implementation choices you make.
@aaronpk
aaron.pk/oauth2
Implementing an OAuth 2 ServerChoose which grant types you want to support
Authorization Code – for traditional web apps Implicit – for browser-based apps and mobile appsPassword – for your own website or mobile appsClient Credentials – if applications can access resources on
their own
Choose whether to support Bearer tokens, MAC or both
If using Bearer tokens, choose whether to use a DB lookup or use self-container tokens
Define appropriate scopes for your service@aaronpk
Access TokensBearer tokens vs
MAC tokens
@aaronpkaaron.pk/oauth2
Bearer Tokens
GET /1/profile HTTP/1.1 Host: api.example.com Authorization: Bearer B2mpLsHWhuVFw3YeLFW3f2
@aaronpk
Bearer tokens are a cryptography-free way to access protected resources.
Relies on the security present in the HTTPS connection, since the request itself is not signed.
Application developers do not need to do any cryptography, they just pass the token string in the header.
aaron.pk/oauth2
aaron.pk/oauth2
Dangers of Using Bearer TokensRequests are not signed, so are vulnerable to
reply attacks if someone intercepts the token.
When storing tokens in cookies, must ensure the cookie is only sent via an https connection.
If a token is leaked, there is a large potential for abuse.
@aaronpk
aaron.pk/oauth2
Security Recommendationsfor Clients Using Bearer TokensSafeguard bearer tokens
Validate SSL certificates
Always use https
Don’t store bearer tokens in plaintext cookies
Issue short-lived bearer tokens
Don’t pass bearer tokens in page URLs
@aaronpk
MAC TokensGET /1/profile HTTP/1.1 Host: api.example.com Authorization: MAC id="jd93dh9dh39D", nonce="273156:di3hvdf8”, mac="W7bdMZbv9UWOTadASIQHagZyirA="
@aaronpk
MAC tokens provide a way to make authenticated requests with cryptographic verification of the request.
Similar to the original OAuth 1.0 method of using signatures.
Application developers must sign each request, preventing forgery and replay even when requests are sent in the clear.
aaron.pk/oauth2
Bearer, MAC, or Both?Should you support Bearer tokens, MAC tokens or
both?
MAC tokens are technically safer and more secure
Application developers will prefer working with Bearer tokens since it is easier
@aaronpk
aaron.pk/oauth2
Scalability ConcernsToken lookups from a database can become a
bottleneck.
Can be addressed by heavy use of caching to avoid DB lookups
Can be addressed by a good master/slave database architecture
An alternative is to use “self-encoded” tokens where all the needed information is contained within the token string itself, avoiding the need to do a database lookup
@aaronpk
aaron.pk/oauth2
Self-Encoded TokensThe token is a string which is encrypted or
signed
The string contains all necessary information to avoid doing a database lookup
These tokens cannot be revoked, so must expire frequently (requires heavy use of the refresh_token grant type)
Can be implemented with either Bearer or MAC tokens
@aaronpk
aaron.pk/oauth2
DB Token Lookups vs Self-Encoded TokensToken table probably looks like
Token User ID Expiration Date Scopes
Instead, encode that into a JSON payload which *is* the token:
{“user_id”:1000,”exp”:1355429676,”scopes”:[“email”,”payment”]}
See JSON Web Signature for example of signing this token
@aaronpk
aaron.pk/oauth2
JSON Web Signaturehttp://tools.ietf.org/html/draft-ietf-jose-json-web-signature-07
@aaronpk
{ "typ":"JWT", "alg":"HS256”}
{ "usr":"username", "exp":1300819380, "scope":["profile"]}
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9
Data Base64 Encoded
eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ
Signature dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOE
aaron.pk/oauth2
JSON Web Signature
@aaronpk
Complete Token Example:
eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
Header, data, signature are base64 encoded and concatenated with a “period” between each.
aaron.pk/oauth2 @aaronpk
oauth.net
aaron.pk/oauth2
oauth.net Websitehttp://oauth.net
Source code available on Github github.com/aaronpk/oauth.net
Please feel free to contribute to the website
Contribute new lists of libraries, or help update information
@aaronpk
aaron.pk/oauth2 @aaronpk
github.com/aaronpk/oauth.net
Thanks.
Aaron Parecki
@aaronpk
aaronparecki.com
github.com/aaronpk