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

OAuth and OpenID Connect in Depth

OAuth and OpenID Connect in Depth

Aaron Parecki

June 06, 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 OAuth 2.0 and OpenID Connect in Depth June 2018
  2. © Okta and/or its affiliates. All rights reserved. Okta Confidential

    Aaron Parecki Author, OAuth 2.0 Simplified Maintainer of oauth.net
  3. 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
  4. Authentication • Process of verifying the identity of a user.

    • Making sure the person who is trying to enter into your application is the same person who they claim to be • Usually involves storing and managing passwords
  5. 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
  6. 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.
  7. 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
  8. 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
  9. 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
  10. 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
  11. 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
  12. 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"}
  13. 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
  14. © Okta and/or its affiliates. All rights reserved. Okta Confidential

    Javascript Apps Implicit Flow - No Client Secret
  15. 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
  16. 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
  17. 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.
  18. PKCE: Proof Key for Code Exchange RFC 7636: Pioneered by

    Google • Like an on-the-fly client secret
  19. 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")
  20. 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
  21. 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
  22. 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
  23. 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
  24. 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
  25. 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.
  26. 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!
  27. 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
  28. © 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.
  29. 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" }
  30. 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" }
  31. 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. 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. 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. 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" }
  35. OpenID Connect • An Identity protocol built on top of

    OAuth 2.0 • ID Token • /userinfo – for getting more information about the user • Standard set of scopes • openid • profile • email • address • phone • offline_access
  36. If User Allows Access https://example.com/ #id_token=eyJraWQiOiJiRmxZbmkzLXRhMXFSa0lFellHc2tLeFFRVUJvczZnOU9RQnRmNm9x cUxJIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiIwMHVjcTNid2o0V25JcTNnejBoNyIsIm5hbWU iOiJQYWRtYS0yIEdvdmluZGFyYWphbHUiLCJsb2NhbGUiOiJlbi1VUyIsInZlciI6MSwiaXNzI joiaHR0cHM6Ly9wYWRtYWdvdmluZGFyYWphbHUub2t0YXByZXZpZXcuY29tL29hdXRoMi9kZWZ hdWx0IiwiYXVkIjoiMG9hZDlydTd0endmNUFqcGIwaDcgIiwiaWF0IjoxNTI0NTk0OTEwLCJle

    HAiOjE1MjQ1OTg1MTAsImp0aSI6IklELklfNUc4RzhWdXowMHJvYl9aSzlja3J0T0pseVdwNzh xMU5naGV2QlJ6dkEiLCJhbXIiOlsicHdkIl0sImlkcCI6IjAwb2NxM2J3aTFoTnpRT3B5MGg3I iwibm9uY2UiOiJhYmMiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJwYWRtYS5nb3ZpbmRhcmFqYWx 1QG9rdGEuY29tIiwiZ2l2ZW5fbmFtZSI6IlBhZG1hIiwibWlkZGxlX25hbWUiOiJLcmlzaG5hI iwiZmFtaWx5X25hbWUiOiJHb3ZpbmRhcmFqYWx1Iiwiem9uZWluZm8iOiJBbWVyaWNhL0xvc19 BbmdlbGVzIiwidXBkYXRlZF9hdCI6MTUyNDU5NDM2MSwiYXV0aF90aW1lIjoxNTI0NTk0OTA3f Q.HvMYW8XbdCf1BWZfHQ1odaAYJjZqKkh1NUkHW0clk6J7pYunn8jllbIp0IhSjcCn6PBIlZPr rE0dkuyjvdHjVI8ALQNwtM7FnIs9H6gCH0oONx4EL4KEf4d_w46qeqsCwMClvNoaE3c2I5kONu JUlaefbnr6Al_y9z5mvLyDynf9IjrOyTPoIrgk9V46l28Aulp4dJhqBtZfpYyVbKrXawHSO5Fv KTDMPBhQgxt0_6PKG7sSkhbMeBicIc35SJJaXt81KSfkYDUp5s1UQ74ATHrtLe7HMU1yp_Kajg YUKxMXO5NiXpeNEHzarAOWzLHblrQcgkpuJbY3KM1HHg&state=xyz1234 The user is redirected back to the redirect_uri with an ID token
  37. ID Token: JWT eyJraWQiOiJiRmxZbmkzLXRhMXFSa0lFellHc2tLeFFRVUJvczZnOU9RQnRmNm9xcUxJIiwiYWxn IjoiUlMyNTYifQ . eyJzdWIiOiIwMHVjcTNid2o0V25JcTNnejBoNyIsIm5hbWUiOiJQYWRtYS0yIEdvdmluZGFyYWph bHUiLCJsb2NhbGUiOiJlbi1VUyIsInZlciI6MSwiaXNzIjoiaHR0cHM6Ly9wYWRtYWdvdmluZGFy YWphbHUub2t0YXByZXZpZXcuY29tL29hdXRoMi9kZWZhdWx0IiwiYXVkIjoiMG9hZDlydTd0endm NUFqcGIwaDcgIiwiaWF0IjoxNTI0NTk0OTEwLCJleHAiOjE1MjQ1OTg1MTAsImp0aSI6IklELklf

    NUc4RzhWdXowMHJvYl9aSzlja3J0T0pseVdwNzhxMU5naGV2QlJ6dkEiLCJhbXIiOlsicHdkIl0s ImlkcCI6IjAwb2NxM2J3aTFoTnpRT3B5MGg3Iiwibm9uY2UiOiJhYmMiLCJwcmVmZXJyZWRfdXNl cm5hbWUiOiJwYWRtYS5nb3ZpbmRhcmFqYWx1QG9rdGEuY29tIiwiZ2l2ZW5fbmFtZSI6IlBhZG1h IiwibWlkZGxlX25hbWUiOiJLcmlzaG5hIiwiZmFtaWx5X25hbWUiOiJHb3ZpbmRhcmFqYWx1Iiwi em9uZWluZm8iOiJBbWVyaWNhL0xvc19BbmdlbGVzIiwidXBkYXRlZF9hdCI6MTUyNDU5NDM2MSwi YXV0aF90aW1lIjoxNTI0NTk0OTA3fQ . HvMYW8XbdCf1BW- ZfHQ1odaAYJjZqKkh1NUkHW0clk6J7pYunn8jllbIp0IhSjcCn6PBIlZPrrE0dkuyjvdHjVI8ALQ NwtM7FnIs9H6gCH0oONx4EL4K-Ef4d_w46qeqsCwMClvNoaE3c2I5-kON- uJUlaefbnr6Al_y9z5mvLyDynf9IjrOyTPoIrgk9V46l28Aulp4dJhqBtZfpYyVbKrXawHSO5FvK TDMPBhQgxt0_6PKG7sSkhbMeBicIc35SJJaXt81KSfkYDUp5s1UQ74ATHrtLe7HMU1yp_KajgYUK xMXO5NiXpeNEHzarAOWzLHblrQcgkpuJbY3KM1HHg header payload signature
  38. Decoded ID Token header . { "sub": "00ucq3bwj4WnIq3gz0h7", "ver": 1,

    "iss": "https://authorization-server.com/oauth2/ausd1nry9hBoyvKrY0h7", "aud": "0oacww4sy8YYS1gOw0h7", "iat": 1524237221, "exp": 1524240821, "nonce": "nonce", "updated_at": 1524606533, "auth_time": 1524606562 } . signature
  39. Verifying the JWT • Fetch the public key of the

    server that issued the token • Verify the signature matches
  40. • issuer (iss) – does the token originate from the

    right auth server? • audience (aud) – is the token intended for my application? • expiry time (exp) – has the current time already passed the exp time? • issued at time (iat) – is the current time too far from the issued time? • nonce - does it match to the nonce passed in the request? Validating the Claims
  41. OpenID Connect - Authorization Code • Exchange the code for

    an ID Token • No need to verify the signature since the token was obtained via a secure backchannel
  42. Remote ID Token Validation Response { "active": "true", "aud": "0oacww4sy8YYS1gOw0h7",

    "exp": 1524240821, "iat": 1524237221, "iss": "https://auth-server/ausd1nry9hBoyvKrY0h7" }
  43. 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
  44. 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
  45. New Access Token in the Response { "access_token": "RsT5OjbzRn430zqMLgV3Ia", "expires_in":

    3600, "refresh_token": "64d049f8b21191e12522d5d96d5641af5e8" }
  46. • Redirect URLs must be registered per client • Redirect

    URLs can have a custom scheme (example://redirect) • When an authorization request is made, the server verifies that the redirect URL in the request matches one that is registered to that client ID Redirect URL Registration 93
  47. 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
  48. © Okta and/or its affiliates. All rights reserved. Okta Confidential

    Defining Scopes 108 • Read / Write • Restrict access to sensitive information • e.g. private repos on GitHub • By functionality • e.g. Google Drive, YouTube, Gmail • Billable resources
  49. © Okta and/or its affiliates. All rights reserved. Okta Confidential

    Presenting Scopes to the User 109 • 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"
  50. © Okta and/or its affiliates. All rights reserved. Okta Confidential

    Allow the user to modify the scopes granted 112