building javascript and mobile/native clients for token...
TRANSCRIPT
Building JavaScript and mobile/native Clients for
Token-based Architectures
@brocklallen & @leastprivilege
https://identityserver.io
Brock Allen & Dominick Baier
2@leastprivilege / @brocklallen
The big Picture
Browser
Native App
Server App"Thing"
Web App
Web API Web API
Web API
Security Token Service
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@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@leastprivilege / @brocklallen
Clients
Browser
Native App
Web API
OAuth 2.0
OAuth 2.0
Security Token ServiceOpenID Connect
OpenID Connect
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@leastprivilege / @brocklallen
Local Logon UI vs Redirect/Server-rendered
UsernamePassword
Login
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)
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
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
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
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
}
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)
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
15@leastprivilege / @brocklallen
More identity data
• Might need more than sub (subject) claim
• scope used to ask for more identity data
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
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
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();
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
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
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
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
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/
24@leastprivilege / @brocklallen
Using a web server for driving the authentication workflow
authentication request
render UI & workflow
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)
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)
27@leastprivilege / @brocklallen
Receiving the response
GET com.mycompany.nativeapp://cb
#id_token=x12f…zsz&code=818…1299
callback
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
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"
}
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
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"
}
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
33@leastprivilege / @brocklallen
thank you!get slides from https://speakerdeck.com/leastprivilege