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

Securing Your APIs with OAuth 2.0

Aaron Parecki
September 20, 2019

Securing Your APIs with OAuth 2.0

Presented at API Days Melbourne 2019

In this talk, you’ll learn how to use OAuth 2.0 to secure access to your APIs. OAuth is an authorization protocol which enables applications to access data on behalf of users without needing to know their username and password. This enables many use cases such as easily enabling multi-factor authorization for your users, and better separation of concerns of all your backend services. We’ll look at how to use JWT access tokens, as well as the tradeoffs that come with them. We’ll look at how to design scopes that allow granular access to various parts of your backend services. We’ll also look at how to design a microservices architecture protected by OAuth at a gateway.

Aaron Parecki

September 20, 2019
Tweet

More Decks by Aaron Parecki

Other Decks in Technology

Transcript

  1. RFC6749 RFC6750 CLIENT TYPE AUTH METHOD GRANT TYPE RFC6819 RFC7009

    RFC7592 RFC7662 RFC7636 RFC7591 RFC7519 BUILDING YOUR APPLICATION RFC8252 OIDC RFC8414 STATE PARAM TLS CSRF UMA 2 FAPI RFC7515 RFC7516 RFC7517 RFC7518 TOKEN BINDING POP SECURITY BCP CIBA HTTP SIGNING MUTUAL TLS SPA BCP JARM JAR TOKEN EXCHANGE DPOP
  2. @aaronpk so... how can I let an app access my

    data without giving it my 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 ▸ Client Credentials: for machine-to-machine authentication
  4. @aaronpk ROLES IN OAUTH OAuth Server (Authorization Server) aka the

    token factory API (Resource Server) The Application (Client) The User (Resource Owner) Device (User Agent)
  5. 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 “Yelp”, it wants to access my contacts AS: Here is a temporary code the app can use App: Here is the temporary code, and my secret, please give me a token User: Here is the temporary code, please use this to get a token AS: Here is an access token! App: Please let me access this user’s data with this access token! User Agent App OAuth Server API ?
  6. Front Channel Back Channel https://accounts.google.com/?... Passing data via the browser's

    address bar The user, or malicious software, can modify the requests and responses Sent from client to server HTTPS request from client to server, so requests cannot be tampered with
  7. Back Channel Benefits ‣ The application knows it's talking to

    the right server ‣ Connection from app to server can't be tampered with ‣ Response from the server can be trusted because it came back in the same connection
  8. Front Channel Benefits https://accounts.google.com/?... ‣ Lets the server prompt the

    user for additional auth factors without the client involved ‣ The user being involved enables them to give consent ‣ Doesn't require the receiver to have a publicly routable IP
 (e.g. can work on a phone)
  9. The app builds the auth link https://authorization-server.com/auth • response_type=code -

    indicates that your app 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=contacts - 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 Front Channel
  10. The user is redirected back to the application with an

    authorization code https://example.com/callback?error=access_denied&state=1234xyz The user is redirected back to the application with an error code If User Denies If User Allows https://example.com/callback? code=AUTH_CODE_HERE& state=1234zyx Front Channel
  11. Verify State • The application verifies the state matches the

    value it started with • This lets the application have more confidence that it isn't trying to exchange an attacker's authorization code The app must do this because it received the authorization code via the front channel! Front Channel
  12. Exchange the Code for an Access Token POST https://api.authorization-server.com/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 Back Channel
  13. Exchange the Code for an Access Token POST https://api.authorization-server.com/token Content-type:

    application/x-www-form-urlencoded grant_type=authorization_code& code=AUTH_CODE_HERE& redirect_uri=REDIRECT_URI& client_id=CLIENT_ID& client_secret=CLIENT_SECRET Back Channel
  14. 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"} Back Channel
  15. Public Clients Confidential Clients Application running on a server Has

    the ability to keep strings secret since code is running in a trusted environment The application can't keep strings secret JavaScript/Single-Page apps: "view source" Native apps: decompile and extract strings
  16. Problem: • The authorization server returns the authorization code in

    the front channel • so it can't guarantee it was actually received by the correct application • it needs a way to verify that the correct application is using it to get a token • Normally the client_secret solves this, but we can't use a secret!
  17. User: I’d like to use this great app App: Please

    go to the authorization server to grant me access, take this hash with you User: I’d like to log in to this app, here's the hashed secret it gave me AS: Here is a temporary code the app can use App: Here's the code, and the plaintext secret, please give me a token User: Here is the temporary code, please use this to get a token AS: Let me verify the hash of that secret... ok here is an access token! App: Please let me access this user’s data with this access token! App: Hang on while I generate a new secret and hash it User Agent App OAuth Server API ?
  18. OAuth Server (Authorization Server) aka the token factory API (Resource

    Server) The Application (Client) The User's Device (User Agent)
  19. OAuth Server (Authorization Server) aka the token factory API (Resource

    Server) The Application (Client) The User's Device (User Agent)
  20. Scope • Allows an application to request a limited-capability access

    token • Limits what an access token can do within what a user is already allowed to do • Is not a way to build a permissions system
  21. are you building an app? are you building an API?

    Authorization: Bearer RsT5OjbzRn430zqMLgV3Ia just use the token parse/extract/introspect the token { "sub": "{USER_ID}", "aud": "{CLIENT_ID}", "exp": 1524240821, "scp": "create" }
  22. Pros • Can be revoked by deleting from the database

    • Can easily show a list of active tokens to the user Reference Tokens Cons • Requires storing all active tokens • API must check the validity with either a DB lookup or HTTP request Best for • Small scale APIs with an integrated OAuth server
  23. Pros • Requires no storage • Better separation of concerns

    (no shared storage between authorization server and API) • Can be validated at the API without a DB/HTTP lookup Self-Encoded Tokens Cons • Cannot be revoked without storing additional information • Cannot get a list of all active tokens Best for • Large-scale distributed architectures, and using an external OAuth server
  24. A JWT Access Token eyJraWQiOiJvQ1JjR3RxVDhRV2tJR0MyVXpmcEZUczVqSkdnM00zSTNOMHgtZDJhSFNNIiwiYWxn IjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULkp3eVRTcTlqNDU0bDNTNmRTM1VTV1hMVVpwe kdKdWNSd1ZEbFZCNWNIc3cuVVM1V1NGYVFiQllUMC9GM2tjMG8vK1ZUY3VZZzdwVnZqZXZTT3hkU HhCMD0iLCJpc3MiOiJodHRwczovL2Rldi0zOTYzNDMub2t0YXByZXZpZXcuY29tL29hdXRoMi9kZ WZhdWx0IiwiYXVkIjoiYXBpOi8vZGVmYXVsdCIsImlhdCI6MTU0MzgwMzAyNSwiZXhwIjoxNTQzO DA2NjI1LCJjaWQiOiIwb2FoenBwM3RjcEZyZmNXSTBoNyIsInVpZCI6IjAwdWkwZmpraWV5TDQ2b

    WEwMGg3Iiwic2NwIjpbIm9mZmxpbmVfYWNjZXNzIiwicGhvdG8iXSwic3ViIjoiaW5xdWlzaXRpd mUtYWxiYXRyb3NzQGV4YW1wbGUuY29tIn0.ncVkzcc6qrFJSXE3-5UsRu_kHvbwIMKYL3PFaMwRe YTquPAcOQ8t93xF0bxbS8wrP0udCDvk6eYq4VbjoFdD59Yy6ltz0OKQl3- g8uFg2RwqTBMOKR0mYtQH0RCr9ORhSsmKolaDDt4TcRX78ZOAyhZ_Qg_UcEoHM4uZikpzBJYpYKb CCfbx-6FzYyHuvevSFzURISYpSHv3nbzirkEzKbOv7eZlg1cCYBdUoGuVBskyHxfMxFpoKQU3mwI FdlQJR8LZ8hA_5ZdYjjMeSXfjnhlP2rppJiHy1NreGXXcUsUA74V2t_keY44deTrnPgoFOSe9Ich Wqcj6sDMDutC4ag
  25. A JWT Access Token { "typ": "JWT", "alg": "RS256", "kid":

    "oCRcGtqT8QWkIGC2UzfpFTs5jJGg3M3I3N0x-d2aHSM" } { "ver": 1, "jti": "AT.JwyTSq9j454l3S6dS3USWXLUZpzGJucRwVDlVB5cHsw.US5WSFaQbBYT0/F3kc0o/+VTcuYg7pVvjevSOxdPxB0=", "iss": "https://dev-396343.oktapreview.com/oauth2/default", "aud": "api://default", "iat": 1543803025, "exp": 1543806625, "cid": "0oahzpp3tcpFrfcWI0h7", "uid": "00ui0fjkieyL46ma00h7", "scp": [ "offline_access", "photo" ], "sub": "[email protected]" } header claims
  26. Access Token Validation The Fast Way The Strong Way Inspect

    the JWT Check the expiration timestamp Validate the cryptographic signature Check the token at the introspection endpoint eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZS I6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImp0aSI6ImI5ZDRhNzViLTA2MDMtNDgxYy1hM jgyLTY3YTk0NDJiNGRkNiIsImlhdCI6MTUzMjQwMDkyMiwiZXhwIjoxNTMyNDA0NTIyfQ.S jYROEt8lZpEOq1eKh3OxRmRk3xttOXZeD5yW8aW2k8 { "sub": "1234567890", "name": "John Doe", "admin": true, "jti": "b9d4a75b-0603-481c-a282-67a9442b4dd6", "iat": 1532400922, "exp": 1532404522 } POST https://authorization-server.com/introspect token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3OD &client_id={CLIENT_ID} &client_secret={CLIENT_SECRET}
  27. Rejecting Revoked Tokens 1:00 2:00 3:00 4:00 5:00 6:00 7:00

    expired 0:00 Local Validation Remote Introspection User revokes application
  28. API Gateway Token Validation API Gateway CUSTOMER API BILLING API

    ORDER API LOCAL VALIDATION TOKEN INTROSPECTION
  29. @aaronpk DIFFERENT LIFETIMES FOR DIFFERENT USERS/SCOPES ACCESS TOKEN 1 HOUR

    REFRESH TOKEN 24 HOURS ACCESS TOKEN 24 HOURS REFRESH TOKEN UNLIMITED ACCESS TOKEN 4 HOURS Admin Users Consumer Users Privileged Scopes Requires admin users to log in every day Best UX, log in once and appear to be logged in forever Prevent applications from using privileged scopes without the user being present