33
Building JavaScript and mobile/native Clients for Token-based Architectures [email protected] @brocklallen & @leastprivilege https://identityserver.io Brock Allen & Dominick Baier

Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

Building JavaScript and mobile/native Clients for

Token-based Architectures

[email protected]

@brocklallen & @leastprivilege

https://identityserver.io

Brock Allen & Dominick Baier

Page 2: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

2@leastprivilege / @brocklallen

The big Picture

Browser

Native App

Server App"Thing"

Web App

Web API Web API

Web API

Security Token Service

Page 3: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

*

*

Page 4: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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*

Page 5: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

5@leastprivilege / @brocklallen

Clients

Browser

Native App

Web API

OAuth 2.0

OAuth 2.0

Security Token ServiceOpenID Connect

OpenID Connect

Page 6: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 7: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

7@leastprivilege / @brocklallen

Local Logon UI vs Redirect/Server-rendered

UsernamePassword

Login

Page 8: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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)

Page 9: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 10: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 11: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 12: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

}

Page 13: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

13@leastprivilege / @brocklallen

Validating id tokens

• Steps to validate:

1. Base64Url decode id_token and parse into JSON (formatting step)

2. Verify nonce is same as sent in request (prevents XSRF/replay)

3. Validate signature on token (establishes trust [requires crypto])

4. Validate iss same as issuer of OIDC OP (establishes trust)

5. Validate aud same as this client's identifier (prevents privilege escalation)

6. Validate exp is still valid (prevents stale tokens)

Page 14: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

14@leastprivilege / @brocklallen

oidc-client

• 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

Page 15: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

15@leastprivilege / @brocklallen

More identity data

• Might need more than sub (subject) claim

• scope used to ask for more identity data

Page 16: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 17: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

17@leastprivilege / @brocklallen

Requesting access token

• Add "token" to response_typeparameter 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_tokenaccess_token

access_token

user profile

id_tokentoken

Page 18: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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();

Page 19: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 20: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 21: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 22: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 23: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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/

Page 24: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

24@leastprivilege / @brocklallen

Using a web server for driving the authentication workflow

authentication request

render UI & workflow

Page 25: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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)

Page 26: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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_numbercode_verifier = random_numbercode_challenge = hash(code_verifier)

Page 27: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

27@leastprivilege / @brocklallen

Receiving the response

GET com.mycompany.nativeapp://cb

#id_token=x12f…zsz&code=818…1299

callback

Page 28: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 29: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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"

}

Page 30: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 31: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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"

}

Page 32: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

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

Page 33: Building JavaScript and mobile/native Clients for Token ... · •Cookies are the typical approach for server-side applications –But not appropriate for modern JavaScript apps •Modern

33@leastprivilege / @brocklallen

thank you!get slides from https://speakerdeck.com/leastprivilege