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

Building JavaScript and mobile/native Clients for Token-based Architectures

Building JavaScript and mobile/native Clients for Token-based Architectures

NDC London 2017

Dominick Baier

January 18, 2017
Tweet

More Decks by Dominick Baier

Other Decks in Programming

Transcript

  1. Building JavaScript and mobile/native Clients for Token-based Architectures [email protected] @brocklallen

    & @leastprivilege https://identityserver.io Brock Allen & Dominick Baier
  2. 2 @leastprivilege / @brocklallen The big Picture Browser Native App

    Server App "Thing" Web App Web API Web API Web API Security Token Service
  3. 3 @leastprivilege / @brocklallen Security Protocols (I) Browser Native App

    Server App "Thing" Web App Web API Web API Web API OpenID Connect* Security Token Service * *
  4. 4 @leastprivilege / @brocklallen Security Protocols (II) Browser Native App

    Server App "Thing" Web App Web API Web API Web API OAuth 2.0 OAuth 2.0 OAuth 2.0 OAuth 2.0 OAuth 2.0 OAuth 2.0 Security Token Service * * OpenID Connect*
  5. 5 @leastprivilege / @brocklallen Clients Browser Native App Web API

    OAuth 2.0 OAuth 2.0 Security Token Service OpenID Connect OpenID Connect
  6. 6 @leastprivilege / @brocklallen Token-based Clients… Clients Web API Security

    Token Service Users (1) Authenticate, establish session (2) identity token, access token (3) process response, validate identity token (4) use access token
  7. 8 @leastprivilege / @brocklallen Modern/Pure JavaScript apps • Client –

    Browser-based – Entirely JavaScript (SPA) – Dynamic rendering all client side • Sever • Thin server • Static content (HTML, JS, CSS, etc.) • Ajax endpoints (HTTP APIs)
  8. 9 @leastprivilege / @brocklallen No more cookies for security •

    Cookies are the typical approach for server-side applications – But not appropriate for modern JavaScript apps • Modern apps don't have/use server-side HTML framework – SPAs (or mobile apps) are doing the UI client-side • APIs can't use cookies – API might be cross-domain – Cookies don't make sense for non-browser clients – Cross-site request forgery (XSRF) security issues
  9. 10 @leastprivilege / @brocklallen Discovery https://authority { "issuer": "https://authority", "jwks_uri":

    "https://authority/.well-known/jwks", "authorization_endpoint": "https://authority/authorize", "token_endpoint": "https://authority/token", "userinfo_endpoint": "https://authority/userinfo", "frontchannel_logout_supported": true, "scopes_supported": [ "openid", "profile", "email", "address", "phone", "offline_access", "api" ], "grant_types_supported": [ "authorization_code", "client_credentials", "password", "refresh_token", "implicit" ], } /.well-known/openid-configuration
  10. 11 @leastprivilege / @brocklallen Authentication in JS-based apps • OpenId

    Provider (OP) – Issues tokens • 1) Client makes request to OP – User authenticates – User consents (optional) • 2) OP returns to client – Accept id token – Client validates id token bob secret id_token
  11. 12 @leastprivilege / @brocklallen Id tokens • Format is JSON

    web token (JWT) eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMD.4MTkzODAsDQogImh0dHA6Ly9leGFt Header Claims Signature { "typ": "JWT", "alg": "RS256", "kid": "mj399j…" } { "iss": "https://idsrv3", "exp": 1340819380, "aud": "app1", "nonce": "289347898934823", "sub": "182jmm199", "email": "[email protected]", "email_verified": true, "amr": "password", "auth_time": 12340819300 }
  12. 13 @leastprivilege / @brocklallen Validating id tokens • Steps to

    validate: 1. Verify state is same as sent in request (prevents XSRF/replay) 2. Base64Url decode id_token and parse into JSON (formatting step) 3. Verify nonce is same as sent in request (prevents XSRF/replay) 4. Validate signature on token (establishes trust [requires crypto]) 5. Validate iss same as issuer of OIDC OP (establishes trust) 6. Validate aud same as this client's identifier (prevents privilege escalation) 7. Validate exp is still valid (prevents stale tokens)
  13. 14 @leastprivilege / @brocklallen OidcClient • JavaScript helper class that

    implements OIDC protocol – Includes id_token validation • Including crypto implementation – Heavy use of promises • http://github.com/IdentityModel/oidc-client-js – Also available via npm
  14. 15 @leastprivilege / @brocklallen More identity data • Might need

    more than sub (subject) claim • scope used to ask for more identity data
  15. 16 @leastprivilege / @brocklallen More identity data with user profile

    • Id token might become too large – Needs to fit into URL • OIDC defines user info endpoint – Ajax call to load user profile – Requires authorization with an access token obtained in OIDC request
  16. 17 @leastprivilege / @brocklallen Requesting access token • Add "token"

    to response_type parameter to authorization endpoint • More validation required (same as before, plus): – Hash access token and compare left half to at_hash in id token (ensures id token is paired with access token) id_token access_token access_token user profile id_token token
  17. 18 @leastprivilege / @brocklallen Using access token to call user

    profile • Access token passed as Authorization HTTP request header • Response is JSON of user profile based upon requested scopes var xhr = new XMLHttpRequest(); xhr.onload = function () { var user_profile = JSON.parse(xhr.response); } xhr.open("GET", user_profile_endpoint); xhr.setRequestHeader("Authorization", "Bearer " + access_token); xhr.send();
  18. 19 @leastprivilege / @brocklallen Calling other web APIs • APIs

    use access token from same OIDC OP • Just need to request more scopes access_token access_token JSON scope: api1
  19. 20 @leastprivilege / @brocklallen Logout • Throw away tokens in

    client • Signing out of OIDC OP – Must make request to OP • Post logout redirect – Must pass redirect URL as post_logout_redirect_uri – Must pass original id token as id_token_hint
  20. 21 @leastprivilege / @brocklallen Token management • Token storage –

    localStorage – sessionStorage – indexedDb • Token expiration – Access tokens expire (1h, 10h, 1d, 30d, whatever) – Need a way to manage this lifetime • Wait for 401 from API • Renew prior to expiration
  21. 22 @leastprivilege / @brocklallen Renewing tokens • Request new token

    in a hidden iframe – only possible if no user interaction is required JS app iframe /authorize?...&prompt=none
  22. 23 @leastprivilege / @brocklallen Native Clients • Applications that have

    access to native platform APIs – desktop or mobile – more options / features • OAuth 2.0 / OpenID Connect for native applications – https://tools.ietf.org/wg/oauth/draft-ietf-oauth-native-apps/
  23. 24 @leastprivilege / @brocklallen Using a web server for driving

    the authentication workflow authentication request render UI & workflow
  24. 25 @leastprivilege / @brocklallen Browser types • Embedded web view

    – private browser & private cookie container – e.g. WinForms or WPF browser control • Authentication broker – "special" browsers (look private but share some cookies) – e.g. Win8 & UWP WebAuthenticationBroker • In-app browser tab / system browser – full blown system browser (including address bar & add-ins) – shared cookie container – e.g. SafariViewController (iOS9) & Chrome Custom Tabs (Android 5)
  25. 26 @leastprivilege / @brocklallen OpenID Connect Hybrid Flow GET /authorize

    ?client_id=nativeapp &scope=openid profile api1 api2 offline_access &redirect_uri=com.mycompany.nativeapp://cb &response_type=code id_token &nonce=j1y…a23 &code_challenge=x929..1921 nonce = random_number code_verifier = random_number code_challenge = hash(code_verifier)
  26. 28 @leastprivilege / @brocklallen Validating the response • Identity token

    validation (section 3.1.3.7) – validate signature • key material available via discovery endpoint – validate iss claim – validate exp (and nbf) – validate aud claim • Authorization code validation (section 3.3.2.10) – hash authorization code and compare with c_hash claim https://openid.net/specs/openid-connect-core-1_0.html
  27. 29 @leastprivilege / @brocklallen Requesting the access token • Exchange

    code for access token – using client id and secret code & code verifier (client_id) { access_token: "xyz…123", refresh_token: "dxy…103", id_token: "xyz…123", expires_in: 3600, token_type: "Bearer" }
  28. 30 @leastprivilege / @brocklallen Next steps • Persist the data

    in protected storage – claims – access token – refresh token • Use access token to communicate with APIs • Use refresh token to get new access tokens when necessary
  29. 31 @leastprivilege / @brocklallen Refreshing an Access Token refresh_token (client_id)

    { access_token: "xyz…123", refresh_token: "jdj9…192j", expires_in: 3600, token_type: "Bearer" }
  30. 32 @leastprivilege / @brocklallen Libaries • C# portable class library

    – desktop .NET, UWP, Xamarin iOS & Android • https://github.com/IdentityModel/IdentityModel.OidcClient • C# NetStandard 1.4 library (WIP) – desktop .NET, .NET Core, Xamarin iOS & Android • Native libraries – https://github.com/openid/AppAuth-iOS – https://github.com/openid/AppAuth-Android