Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OAuth all the things! An Introduction to OAuth

OAuth all the things! An Introduction to OAuth

Aaron Parecki

June 20, 2018
Tweet

More Decks by Aaron Parecki

Other Decks in Technology

Transcript

  1. © Okta and/or its affiliates. All rights reserved. Okta Confidential

    Aaron Parecki Developer Advocate at Okta @aaronpk aaronpk.com
  2. @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
  3. @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
  4. @aaronpk Using an Access Token POST /resource/1/update HTTP/1.1 Authorization: Bearer

    RsT5OjbzRn430zqMLgV3Ia Host: api.authorization-server.com description=Hello+World
  5. @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.
  6. @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
  7. @aaronpk Authorization Server Resource Server The Best App Ever accounts.google.com

    contacts.google.com FriendFinder The User’s Computer
  8. @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!
  9. @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
  10. @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
  11. @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
  12. @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
  13. @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"}
  14. @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
  15. © Okta and/or its affiliates. All rights reserved. Okta Confidential

    Javascript Apps Implicit Flow - No Client Secret
  16. @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
  17. @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
  18. @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.
  19. @aaronpk Redirect URLs for Native Apps Custom URL Scheme: example://redirect

    App-Claimed URL Pattern https://maps.google.com/*
  20. @aaronpk PKCE: Proof Key for Code Exchange RFC 7636: Pioneered

    by Google • Like an on-the-fly client secret
  21. @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")
  22. @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
  23. @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
  24. @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
  25. @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
  26. @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
  27. @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.
  28. @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!
  29. @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
  30. © 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.
  31. @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" }
  32. @aaronpk 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" }
  33. @aaronpk 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" }
  34. @aaronpk 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" }
  35. @aaronpk 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" }
  36. @aaronpk 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. { "access_token": "RsT5OjbzRn430zqMLgV3Ia", "expires_in": 3600, "refresh_token": "b7aab35e97298a060e0ede5b43ed1f70a8" }
  37. @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
  38. @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
  39. @aaronpk New Access Token in the Response { "access_token": "RsT5OjbzRn430zqMLgV3Ia",

    "expires_in": 3600, "refresh_token": "64d049f8b21191e12522d5d96d5641af5e8" }
  40. @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
  41. © 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
  42. © 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"
  43. © Okta and/or its affiliates. All rights reserved. Okta Confidential

    Allow the user to modify the scopes granted !93