Implementing Infinity Login¶
This page goes into some detail about how we offer our OAuth 2.0-compliant solution.
You can also consult the API reference directly.
Requirements¶
Infinity Login
OAuth 2 application already created inside Unbox Studio- Basic understanding of how OAuth 2.0 works
OAuth 2 flows¶
We currently offer only the code
flow, no token
. Additionally, Proof Key for Code Exchange (PKCE) is always required and it supports only the S256
method (no plain text). See the PKCE requirements section at the end of this page.
Configuration¶
Automatic / openid-configuration¶
If your client library supports it you could use this URL directly:
This endpoint describes all available OAuth 2 endpoints which follow the appropriate RFC.
JWKS¶
If you are not using the automatic configuration, then in order to verify the JWT access token on your side, you can retrieve our keys by calling the following:
https://clx-webx-authorization-server.unboxuniverse.io/.well-known/jwks.json
❗ Caution: We rotate these keys from time to time, so do not cache them indefinitely.
Web Application Flow¶
Here is the happy path of the flow between a web app client and XYZ, without Single sign-on (SSO):
client_id
triggers a request to the/authorize
endpoint, redirecting the end user to the Infinity Login server.- The Infinity Login server redirects the user to a login page.
- The login page displays some client information and a QR Code.
- User scans the QRCode with their XYZ mobile app. The result of the scan is that the app presents to the user some information about the login (typically scope of access to their information), and the user consents to this scope of access.
- Infinity Login server notifies the login page to redirect the user to client application (using the client
redirect_uri
). - The client retrieves the response
code
through the callback and then calls the Infinity Login server through the/token
endpoint to exchange it for a valid Infinity Login access token (JWT).
SSO-specific case¶
If the required scopes of access are already consented to (for this specific client) and the end user is already authenticated on the Infinity Login server (most likely via a prior successful login), then the signature mechanism involving XYZ is not required, and the client gets the code
back immediately after the call to /authorize
.
However, if at least one scope is new, the flow becomes identical to the one without SSO involved.
Mobile to XYZ Flow¶
In this flow, the client is a mobile application instead of a browser.
From an Infinity Login server point of view, this is called the headless flow or API flow, and the major difference is that there is no login page.
Additionally, there is no HTTP redirect_uri
used. Everything is done through the exchanges between the mobile application and XYZ.
To use the headless flow you must have the following header in the /authorize
and /login
requests:
How it works:¶
- Client application calls the
/authorize
endpoint and gets thelogin_code_to_sign
(with the header mentioned above). - Client application uses a deeplink to ask the XYZ native app to sign this code.
- XYZ presents the login request.
- End user consents to the access scope, which results in a callback to the client mobile application (also using a deeplink).
- Client mobile application receives the following data from XYZ:
- The original
login_code_to_sign
- The
signature
(or proof) which is thelogin_code_to_sign
signed with the public key - The public key used to sign (encrypt), i.e. the identity which the end user selected to login
- Client mobile application posts this data to the
/login
endpoint, which returns acode
for next call. - Client mobile application posts the freshly received
code
to the/token
endpoint, which returns the final access token.
Once the login part is completed, the flows are essentially the same for both mobile and web. The only exception is that the client mobile application needs to communicate with XYZ using a deeplink.
⭑ Note: We are currently working to provide mobile SDKs, namely React Native, Flutter, Android, and iOS. Please reach out to us if they are still not available or if you wish for something not on this list.
SSO¶
Since we support SSO, if a client application has already approved all its scopes and the user is already authenticated through Infinity Login server, then an immediate callback occurs to the redirect_uri
with the code
for the /token
exchange endpoint.
⭑ Note: You still have to redirect your user with the
/authorize
endpoint as usual to get a new token.
SSO is only available through a browser, and because it uses cookies to make the session happen, they have to be enabled by the end user.
Logout¶
You can perform a logout by redirecting the user to the following URL, which takes them to the logout page:
⚠ Warning: using the logout feature does not invalidate any existing access token that's already issued, but destroys the session the user has within the Infinity Login server.
This is most likely a feature you might want to use if you need to switch user within the same browser session.
Again, this is very specific to SSO.
PKCE requirements¶
https://www.rfc-editor.org/rfc/rfc7636.html#section-6.2
PKCE is a mandatory mechanism to protect the token exchange. You must initiate a request to the /authorize
endpoint with the hash value (code_challenge
) to later use its clear value (code_verifier
) during the token exchange:
- Generate random value with enough entropy, at least 12 characters. This is the
code_verifier
. - Generate the
SHA-256
and encode it in Base64 without the leading. This is thecode_challenge
usingBASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
❗ Caution: Make sure to encode in Base64 without padding!
Implementation examples¶
Here are some simple examples of implementation. There may be better solutions out there. If you use any kind of OAuth 2 client library, there is a good chance that this is already available out of the box.
// In Rust
let mut sha256 = Sha256::new();
sha256.update(code_verifier.as_bytes());
let code_challenge = base64::encode_config(sha256.finish(), base64::URL_SAFE_NO_PAD)
// In Javascript
// Sure this could be better coded
async function generateCodeChallenge(codeVerifier) {
var digest = await crypto.subtle.digest("SHA-256",
new TextEncoder().encode(codeVerifier));
return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_')
}
Another example for React native: https://www.npmjs.com/package/react-native-pkce-challenge
Here's what the JSON looks like:
{
"codeChallenge":"FrKXvAasmPJAnMh9jPOW-HMQouSjPYAwlMU-RP20vLs",
"codeVerifier":"xDshz4RJuwAMLOa8j41R1gR-NhLMv7WoU2LiC-bqrwNpnU70l1mlZocMSh3pABbsWiIHBPKFbPEuFbZy_cQiRWMQjBXoxPY9FUe9STC5h4vJ7wyGKMDKKo9sQtraBScm"
}
Anatomy of the Infinity Login token¶
If you decode the access token, inside it you can find the following claims:
iss
: The issuer, i.e. the Unbox server located athttps://clx-webx-authorization-server.unboxuniverse.io/
sub
: Corresponds to the identifier of the connected end-user, in our case always the public keypub_key_hash
: Corresponds to the hash of thepublic_key
. This is provided for convenience but you could derive it from the sub.aud
: This is yourclient_id
scope
: Consented scope from the end user.storage_token
: Currently not used for the community editioniat
: Timestamp of when the token gets deliveredexp
: Timestamp of when the token expires