How a browser or mobile application obtains an access token from UMS
A browser or mobile application can use the Implicit flow to obtain an access token from User Management Service (UMS) single-sign-on (SSO) that can be used to invoke an OAuth 2.0 protected REST API.
Understanding the Implicit flow
In the Implicit flow, the client is issued an access token directly. This contrasts with the Authorization flow, which issues the client with an authorization code.
When UMS issues an access token, the client identity is verified by using the redirection URI that is used to deliver the access token to the client. The URI must be registered when the client application is registered with UMS SSO. It is not possible to make use of a client secret because a browser cannot keep secrets.
Design Considerations for the custom app
- The client app must register with UMS SSO as an OIDC Relying Party. For example:
Wherecurl -v -k -s -X POST -H "Content-Type:application/json" -u "umsadmin:passw0rd" -d @- "https://<ums-host>/oidc/endpoint/ums/registration" <<+++ { "scope": "openid", "preauthorized_scope": "openid", "introspect_tokens": true, "client_id": "browser", "client_name": "browser", "response_types": ["token"], "grant_types": ["implicit"], "redirect_uris": [ "https://your-browser-app-IP/tokenReceiver.html " ] } +++
grant_types
must be set toimplicit
.response_types
must be set totoken
.redirect_uris
acts as a whitelist, you can specify a list of URIs.Tip: If you want to use wild-cards or regular expressions in theredirect_uris
, you must include
For more information, see Configuring an OpenID Connect Provider to accept client registration requests."allow_regexp_redirects": true
- The browser application requests an access token from the OAuth authorization server, for
example, by making the user's browser visit the
/authorize
endpoint and including a link that redirects to UMS SSO for authentication. For example:<body> <h1>OAuth 2.0 Implicit</h1> <p>Have a look at the URL bar. If there is no token, click <a href="https://<ums-host>/oidc/endpoint/ums/authorize?response_type=token&client_id=browser&scope=openid&state=none&redirect_uri=http://192.168.99.100:8080">here</a></p> </p> ... </body>
In this example, the browser application passes the following parameters:response_type=token
because the app is requesting anaccess_token
(not anid_token
)client_id=browser
: The app needs to identify itself so that the authorization server can verify that theredirect_uri
is one of the preregistered URLs and so that it can also include theclient_id
in the token information.scope=openid
is pre-authorized.state=none
is a short-cut in this example. This parameter is meant to allow the client (browser app) to make sure that it sent the user to the authorization server and prevent any unsolicited invocations. It can also help re-establishing context if the browser app had saved several parameters, such as in HTML5 session storage.redirect_uri
is the URI to come back to after the user has authenticated and given their consent (depending on the scopes).
- When the request is redirected back to the browser application, several parameters are passed in
the URL, including the access token. In the following code snippet,
readTokenFromUrl()
demonstrates how to parse name value pairs out of the URL bar and store them in a complex variable namedparams
.var api_base_url = "https://sample.api.server/rest/objectstore" //construct the target API URL for the service you want to invoke var params = {}; function readTokenFromUrl() { var queryString = location.hash.substring(1); var regex = /([^&=]+)=([^&]*)/g; var m; while (m = regex.exec(queryString)) { params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]); } if (params.access_token==undefined) { addTextNode("access_token", "not available yet"); } else { addTextNode("access_token", params.access_token); addTextNode("scopes", params.scope); addTextNode("token_type", params.token_type); addTextNode("expires_in", params.expires_in); } } function getValue() { var key = document.getElementById("key").value; var xmlhttp = new XMLHttpRequest(); try { xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById("response").innerText=xmlhttp.responseText; } } xmlhttp.open("GET",api_base_url+"/" + key, true); xmlhttp.setRequestHeader("Authorization","Bearer " + params.access_token); xmlhttp.send(); } catch (err) { Console.log(err.message); } } function setValue(key, value) { var key = document.getElementById("key").value; var value = document.getElementById("value").value; var xmlhttp = new XMLHttpRequest(); try { xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4) { if (xmlhttp.status==200) { document.getElementById("response").innerText="success" } } else if (xmlhttp.satus==403) { document.getElementById("response").innerText="not authorized" } } xmlhttp.open("PUT",api_base_url+"/" + key, true); xmlhttp.setRequestHeader("Authorization","Bearer " + params.access_token); xmlhttp.setRequestHeader("Content-Type","application/json"); xmlhttp.send(value); } catch (err) {return err.message; } } function addTextNode(elementId, text) { var textnode = document.createTextNode(text); var parent = document.getElementById(elementId); parent.appendChild(textnode); }
- The code in the custom application can now use the access token to make XML HTTP Requests (XHR)
to invoke OAuth 2.0 protected REST APIs. It must pass the value of the access token with each API
request in the request header
Authorization
.