Share
Embed
Transcript
102 slides
-
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Aaron Parecki @aaronpk aaronpk.com OAuth 2.0 Simplified OWASP Portland July 2018 -
@aaronpk Before OAuth • Apps stored the user’s password •
Apps got complete access to a user’s account • Users couldn’t revoke access except by changing their password • Compromised apps exposed the user’s password -
@aaronpk OAuth is a framework for users to authorize applications
to act on their behalf -
@aaronpk Hotel key cards, but for apps The door doesn’t
need to know who you are -
@aaronpk OAuth 2.0 Terminology • The Application: "Client" • The
API: "Resource Server" • Authorization Server • The User: "Resource Owner" • Access Token -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Part 1: OAuth Clients -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Obtaining an Access Token -
@aaronpk Obtaining an Access Token Applications use an OAuth flow
to obtain an access token • Authorization Code Flow: web apps, native apps • Device Flow: browserless or input-constrained devices • Password: not really OAuth, only for first-party apps • Refresh Token: getting a new access token when it expires -
@aaronpk Using an Access Token POST /resource/1/update HTTP/1.1 Authorization: Bearer
RsT5OjbzRn430zqMLgV3Ia Host: api.authorization-server.com description=Hello+World -
@aaronpk 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. -
@aaronpk Client ID and Secret • A "public client" means
anything where the client cannot keep strings confidential. • Javascript clients: "view source" • Native apps: can decompile and see strings • No secret is used for these clients, only the ID -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Web Server Apps Authorization Code Flow -
@aaronpk Authorization Server Resource Server The Best App Ever User:
I’d like to use this great app App: Please go to the authorization server to grant me access User: I’d like to log in to “The Best App Ever”, it wants write access to my account Authz: Here is a temporary code the app can use App: Here is the temporary code, please give me a token User: Here is the temporary code, please use this to get a token Authz: Here is an access token! App: Please let me access this user’s data with this access token! -
@aaronpk Build the "Log in" link • response_type=code - indicates
that your client expects to receive an authorization code • client_id=CLIENT_ID - The client ID you received when you first created the application • redirect_uri=REDIRECT_URI - Indicates the URL to return the user to after authorization is complete, such as https://example-app.com/callback • scope=photos - A space-separated string indicating which parts of the user's account you wish to access • state=1234zyx - A random string generated by your application, which you'll verify later -
@aaronpk If User Allows https://example.com/auth?code=AUTH_CODE_HERE&state=1234zyx The user is redirected back
to the application with an authorization code https://example.com/auth?error=access_denied The user is redirected back to the application with an error code If User Denies -
@aaronpk Verify State • The application verifies the state matches
the expected value -
@aaronpk Exchange the Code for an Access Token • grant_type=authorization_code
- indicates that this request contains an authorization code • code=CODE_FROM_QUERY - Include the authorization code from the query string of this request • redirect_uri=REDIRECT_URI - This must match the redirect_uri used in the original request • client_id=CLIENT_ID - The client ID you received when you first created the application • client_secret=CLIENT_SECRET - Since this request is made from server- side code, the secret is included -
@aaronpk Exchange the 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 -
@aaronpk Exchange the Code for an Access Token { "access_token":"RsT5OjbzRn430zqMLgV3Ia",
"expires_in":3600, "refresh_token":"64d049f8b21191e12522d5d96d5641af5e8" } The server replies with an access token and expiration time or if there was an error: {"error":"invalid_request"} -
@aaronpk example-app.com Connect with Google Client accounts.google.com email password Authorization
Server accounts.google.com Yes No Allow Example App to access your public profile and contacts? example-app.com/callback Loading… Direct the user to the authorization server response_type=code &redirect_uri=example-app.com/callback &state=00000 User signs in Authorization server redirects back to the app code=XYZ123&state=00000 Exchange authorization code for an access token -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Javascript Apps Implicit Flow - No Client Secret -
@aaronpk Build the "Log in" link • response_type=token - indicates
that your client expects to receive an access token • client_id=CLIENT_ID - The client ID you received when you first created the application • redirect_uri=REDIRECT_URI - Indicates the URI to return the user to after authorization is complete, such as https://example-app.com/callback • scope=photos - A space-separated string indicating which parts of the user's account you wish to access • state=1234zyx - A random string generated by your application, which you'll verify later -
@aaronpk If User Allows https://example.com/auth#token=ACCESS_TOKEN The redirect contains an access
token in the URL https://example.com/auth#error=access_denied The user is redirected back to the application with an error code If User Denies -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Mobile Apps PKCE -
@aaronpk Redirect URLs 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. -
@aaronpk Redirect URLs for Native Apps Custom URL Scheme: example://redirect
App-Claimed URL Pattern https://maps.google.com/* -
@aaronpk PKCE: Proof Key for Code Exchange RFC 7636: Pioneered
by Google • Like an on-the-fly client secret -
@aaronpk PKCE: Proof Key for Code Exchange • First create
a "code verifier", a random string 43-128 characters long. • Compute the SHA256 hash of the code verifier, call that the code challenge • Include code_challenge=XXXXXX and code_challenge_method=S256 in the initial authorization request • Send the code verifier when exchanging the authorization code for an access token • (For clients that can't support SHA256, include the plaintext verifier as the challenge, and set the method to "plain") -
@aaronpk Generate the Code Verifier 4A6hBupTkAtgbaQs39RSELUEqtSWTDTcRzVh1PpxD5YVKllU Generate a random string
43-128 characters long ipSBt30y48l401NGbLjo026cqwsRQzR5KI40AuLAdZ8 The challenge is the SHA256 hash of the verifier string base64url(sha256(code_verifier)) Generate the Code Challenge -
@aaronpk 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 Include the code challenge (the hashed value) in the request -
@aaronpk If User Allows example://auth?code=AUTH_CODE_HERE&state=1234zyx The user is redirected back
to the application with an authorization code example://auth?error=access_denied The user is redirected back to the application with an error code If User Denies -
@aaronpk Exchange the Code for an Access Token Verify state,
then make a POST request: • grant_type=authorization_code - indicates that this request contains an authorization code • code=CODE_FROM_QUERY - Include the authorization code from the query string of this request • redirect_uri=REDIRECT_URI - This must match the redirect_uri used in the original request • client_id=CLIENT_ID - The client ID you received when you first created the application • code_verifier=VERIFIER_STRING - The plaintext code verifier initially created -
@aaronpk Exchange the 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 Note: code verifier used in place of client secret -
@aaronpk Exchange the Code for an Access Token { "access_token":"RsT5OjbzRn430zqMLgV3Ia",
"expires_in":3600", "refresh_token":"64d049f8b2119a12522d5dd96d5641af5e8" } 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. -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
First Party Apps Password Flow -
@aaronpk Exchange the Username and Password for a Token POST
https://api.authorization-server.com/token grant_type=password& username=USERNAME& password=PASSWORD& client_id=CLIENT_ID& client_secret=CLIENT_SECRET The user’s credentials are sent directly! Not a good idea for third party apps! -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Server-to-Server Client Credentials -
@aaronpk Exchange the Client ID and Secret for a Token
POST https://api.authorization-server.com/token grant_type=client_credentials& client_id=CLIENT_ID& client_secret=CLIENT_SECRET No user context in the request, so the access token can only be used to access the application’s resources -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Browserless Devices Device Flow -
@aaronpk Request a Device Code POST https://authorization-server.com/device client_id=CLIENT_ID First the
device requests a device code and user code. -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Request a Device Code { "device_code": "NGU5OWFiNjQ5YmQwNGY3YTdmZTEyNzQ3YzQ1YSA", "user_code": "BDWD-HQPK", "verification_uri": "https://example.com/device", "interval": 5, "expires_in": 1800 } The server responds with a new device code and user code, as well as the URL the user should visit to enter the code. -
@aaronpk NLBLMDPP POST https://example.okta.com/token grant_type=urn:ietf:params:oauth:grant- type:device_code &client_id=CLIENT_ID &device_code=NGU5OWFiNjQ5YmQwNGY3YTdmZTEyNzQ3YzQ1YSA While the
device waits for the user to enter the code and authorize the application, the device polls the token endpoint. { "error": "authorization_pending" } -
@aaronpk POST https://example.okta.com/token grant_type=urn:ietf:params:oauth:grant- type:device_code &client_id=CLIENT_ID &device_code=NGU5OWFiNjQ5YmQwNGY3YTdmZTEyNzQ3YzQ1YSA { "error": "authorization_pending"
} While the device waits for the user to enter the code and authorize the application, the device polls the token endpoint. -
@aaronpk POST https://example.okta.com/token grant_type=urn:ietf:params:oauth:grant- type:device_code &client_id=CLIENT_ID &device_code=NGU5OWFiNjQ5YmQwNGY3YTdmZTEyNzQ3YzQ1YSA { "error": "authorization_pending"
} While the device waits for the user to enter the code and authorize the application, the device polls the token endpoint. -
@aaronpk POST https://example.okta.com/token grant_type=urn:ietf:params:oauth:grant- type:device_code &client_id=CLIENT_ID &device_code=NGU5OWFiNjQ5YmQwNGY3YTdmZTEyNzQ3YzQ1YSA { "error": "authorization_pending"
} While the device waits for the user to enter the code and authorize the application, the device polls the token endpoint. -
@aaronpk POST https://example.okta.com/token grant_type=urn:ietf:params:oauth:grant- type:device_code &client_id=CLIENT_ID &device_code=NGU5OWFiNjQ5YmQwNGY3YTdmZTEyNzQ3YzQ1YSA { "error": "authorization_pending"
} While the device waits for the user to enter the code and authorize the application, the device polls the token endpoint. -
@aaronpk POST https://example.okta.com/token grant_type=urn:ietf:params:oauth:grant- type:device_code &client_id=CLIENT_ID &device_code=NGU5OWFiNjQ5YmQwNGY3YTdmZTEyNzQ3YzQ1YSA { "access_token": "RsT5OjbzRn430zqMLgV3Ia",
"expires_in": 3600, "refresh_token": "b7aab35e97298a060e0ede5b43ed1f70a8" } While the device waits for the user to enter the code and authorize the application, the device polls the token endpoint. -
@aaronpk What is a Refresh Token? • A special token
used to get new access tokens • Requested along with the id_token or access token in the initial step • Usually requires scope: offline_access • Usually not issued to Javascript apps -
@aaronpk Exchange the Refresh Token for an Access Token POST
https://authorization-server.com/token grant_type=refresh_token& refresh_token=REFRESH_TOKEN& redirect_uri=REDIRECT_URI& client_id=CLIENT_ID& client_secret=CLIENT_SECRET -
@aaronpk New Access Token in the Response { "access_token": "RsT5OjbzRn430zqMLgV3Ia",
"expires_in": 3600, "refresh_token": "64d049f8b21191e12522d5d96d5641af5e8" } -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Part 2: OAuth Servers -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Components of an OAuth Server -
@aaronpk Authorization Interface Identify your service Identify the third-party app
List the scopes the app is requesting Identify the developer name Show which user is logged in Allow/Cancel buttons -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
OAuth 2.0 Scopes -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Defining Scopes 89 • Read / Write • Restrict access to sensitive information • e.g. private repos on GitHub • By functionality • e.g. Google Drive, YouTube, Gmail • Billable resources -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Presenting Scopes to the User 90 • Provide clear and straightforward information • Provide enough detail so the user knows what the application can access • Don't provide too much detail that they are overwhelmed and just click "ok" -
© Okta and/or its affiliates. All rights reserved. Okta Confidential
Allow the user to modify the scopes granted 93 -
Thanks! oauth.net oauth2simplified.com the spec, links to libraries, docs my
book! Print, PDF, ePub aaronpk.com @aaronpk