Skip to content

Ultra SSO integration guide

The ultra platform Identity and Access Management (IAM) is provided by an OpenID Connect compliant server.

The ultra platform OpenID Connect server is Keycloak. Each development partner must request a client_id from Ultra.

OpenID Connect is an interoperable authentication protocol based on the OAuth 2.0 family of specifications.

Requesting access from Ultra

Before being able to successfully start this tutorial, you will need to send a client request to the Ultra team to the support@ultra.io email address giving:

  • a description of the purpose of the web application
  • a redirect URL which will be used by our auth server to redirect the user when logged in (we will take https://redirecturi/callback as example in the tutorial)

Once the client_id for your web application has been created by the Ultra team, an email response will be sent back to you with the corresponding client_id (and clientSecret which will be useless for the flow used in the Single Sign On - i.e. SSO).

Domains

For different domains, Ultra provides different URLs that you must use for authentication purposes. These are the ones that are open to the public.

Auth DomainBlockchain networkExample URL
auth.ultra.ioMainnethttps://auth.ultra.io/auth/realms/ultraio/protocol/openid-connect/auth
auth.staging.ultra.ioTestnethttps://auth.staging.ultra.io/auth/realms/ultraio/protocol/openid-connect/auth

Requesting OAuth Authorization Code

Request

Below is an example of a request URL that you can open in the browser windows (Ultra client) to request an OAuth Authorization Code. Replace the parameter values with the ones relevant to your project.

sh
https://auth.staging.ultra.io/auth/realms/ultraio/protocol/openid-connect/auth
?client_id=third-party-client
&response_type=code
&state=fj8o3n7bdy1op5

In this example, the parts above are:

  • http://auth.staging.ultra.io – is the domain on which our authorization server is running (for production environment staging will need to be replaced by https://auth.ultra.io as described in the openId flows documentation)

  • ultraio – is the Ultra Realm

  • third-party-client – is the OAuth client_id you received from the Ultra team (see the above prerequisite)

  • code – is a response_type (OAuth Response Type). This value must be “code” for the OAuth Code Grant flow to work. If you provide a different value here, the request will not work. The response_type is a required parameter in OAuth Code Grant flow,

  • fj8o3n7bdy1op5 – is a RECOMMENDED, opaque value used by the client to maintain state between the request and callback. You will need to generate this random alphanumeric string of characters and include them in the request. The authorization server includes this value when redirecting the user-agent back to the client. The parameter SHOULD be used for preventing cross-site request forgery. The page that handles the response from the authorization server will need to read this value and compare it to the original one that was sent with this request. The two values must match.

Remember that this parameter should be:

  1. Unique per user session.
  2. Secret
  3. Unpredictable (large random value generated by a secure method. Ex.: java.security.SecureRandom).

Response

In the case of a successful request, the authorization server will generate the authorization code and will redirect the client application to a Redirect URI configured in our auth server for this OAuth client.

json
https://redirecturi/callback
?state=fj8o3n7bdy1op5
&session_state=f109bb89-cd34-4374-b084-c3c1cf2c8a0b
&code=0aaca7b5-a314-4c07-8212-818cb4b7e8d0.f109bb89-cd34-4374-b084-c3c1cf2c8a0b.1dc15d06-d8b9-4f0f-a042-727eaa6b98f7

Optional Request Parameters

A request for an authorization code can include other optional parameters:

  • scope – OPTIONAL. The scope of the access request,

  • redirect_uri – OPTIONAL. After completing its interaction with the resource owner, the authorization server directs the resource owner’s user-agent back to the client. The authorization server redirects the user-agent to the client’s redirection endpoint previously established with the authorization server during the client registration process or when making the authorization request. If you include this request parameter in the request, then its value must match the one configured in Ultra authorization server. Otherwise, an error will take place.

Below is a Request URL that contains all required, recommended, and optional request parameters you can use in the request for an OAuth Authorization Code.

sh
https://auth.staging.ultra.io/auth/realms/ultraio/protocol/openid-connect/auth
?client_id=third-party-client
&response_type=code
&scope=blockchainid
&redirect_uri=https://redirecturi/callback
&state=fj8o3n7bdy1op5

Exchanging Authorization Code for the Id token

Once you have the Authorization Code, you are ready to exchange it for an access token. Below is an example of a curl command you can use to exchange an authorization code for an access token. Replace the request parameter values with the ones relevant to your project.

Request

sh
curl --location --request POST 'https://auth.staging.ultra.io/auth/realms/ultraio/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=third-party-client' \
--data-urlencode 'code=0aaca7b5-a314-4c07-8212-818cb4b7e8d0.f109bb89-cd34-4374-b084-c3c1cf2c8a0b.1dc15d06-d8b9-4f0f-a042-727eaa6b98f7' \
--data-urlencode 'redirect_uri=https://redirecturi/callback'

Where:

  • https://redirecturi/callback – is a redirect_uri which is REQUIRED, if the redirect_uri parameter was included in the authorization request to acquire the Authorization Code,
  • authorization_code – is a REQUIRED grant_type parameter which value must be “authorization_code”. If you provide a different value here, the request will not be successful.
  • The value of a code request parameter must be an OAuth Authorization Code that was received from an authorization server. It is this value we are exchanging for an access token.

Response

In case of a successful request, below is an example of a response that contains an idtoken (containing the requested user information / ex: walletId, username, email), an access token and a refresh token.

json
{
    "id_token": "eyJdewfregtrgtgerse6ICItNUlsX2I0cUktdWFvaEI3d244UHY3WEM2UEktU3BNbmZCRnlJZUx6QTJNIn0.eyJleHAiOjE1OTIzNDM5NDEsImlhdCI6MTU5MjM0MzY0MSwiYXV0aF90aW1lIjoxNTkyMzQwODA1LCJqdGkiOiJlYjlhNTc2NS1jYmVhLTQ2ZWMtYTk4NS0wOWFkYTM5NTk5YjIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvYXBwc2RldmVsb3BlcmJsb2ciLCJzdWIiOiIxZGRlM2ZjMy1jNmRiLTQ5ZmItOWIzZC03OTY0YzVjMDY4N2EiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwaG90by1hcHAtY29kZS1mbG93LWNsaWVudCIsInNlc3Npb25fc3RhdGUiOiJmMTA5YmI4OS1jZDM0LTQzNzQtYjA4NC1jM2MxY2YyYzhhMGIiLCJhY3IiOiIwIiwic2NvcGUiOiJwcm9maWxlIiwibmFtZSI6IkthcmdvcG9sb3YiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJnZXkiLCJmYW1pbHlfbmFtZSI6IkthcmdvcG9sb3YifQ.KHCNF0Rn-I7iFosB3oEaWetRw9lhSkkP0-Ef6iW2GAZuuI-GQtZUBDAD_aEDtLTdUpvGL8MKx8Os0qbUZKJJhBhTAJyz2DycgY--ROc_vLbPtJSll-F68tHT6KgC2etbTjpz4Ira6PaLigkT80zGb6tpnQmm1o7a4IGQ40-faKC4fivdfblypGqgRnniOGXMLGpzO2Ln92w1azjFAyOCIBhe3Nlcofjupi26qNGrJKuwBudzZgZCla9RDWm2MUTqMW65AOUpOmiJCd5E4JxbwOuG6H2tbYI2Z-ajQXzzcodmCAWfWu2oRkMaAuNImph8W9tRrqCQ0wlb55tXnUvEuw",
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICItNUlsX2I0cUktdWFvaEI3d244UHY3WEM2UEktU3BNbmZCRnlJZUx6QTJNIn0.eyJleHAiOjE1OTIzNDM5NDEsImlhdCI6MTU5MjM0MzY0MSwiYXV0aF90aW1lIjoxNTkyMzQwODA1LCJqdGkiOiJlYjlhNTc2NS1jYmVhLTQ2ZWMtYTk4NS0wOWFkYTM5NTk5YjIiLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvYXV0aC9yZWFsbXMvYXBwc2RldmVsb3BlcmJsb2ciLCJzdWIiOiIxZGRlM2ZjMy1jNmRiLTQ5ZmItOWIzZC03OTY0YzVjMDY4N2EiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwaG90by1hcHAtY29kZS1mbG93LWNsaWVudCIsInNlc3Npb25fc3RhdGUiOiJmMTA5YmI4OS1jZDM0LTQzNzQtYjA4NC1jM2MxY2YyYzhhMGIiLCJhY3IiOiIwIiwic2NvcGUiOiJwcm9maWxlIiwibmFtZSI6IkthcmdvcG9sb3YiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJnZXkiLCJmYW1pbHlfbmFtZSI6IkthcmdvcG9sb3YifQ.KHCNF0Rn-I7iFosB3oEaWetRw9lhSkkP0-Ef6iW2GAZuuI-GQtZUBDAD_aEDtLTdUpvGL8MKx8Os0qbUZKJJhBhTAJyz2DycgY--ROc_vLbPtJSll-F68tHT6KgC2etbTjpz4Ira6PaLigkT80zGb6tpnQmm1o7a4IGQ40-faKC4fivdfblypGqgRnniOGXMLGpzO2Ln92w1azjFAyOCIBhe3Nlcofjupi26qNGrJKuwBudzZgZCla9RDWm2MUTqMW65AOUpOmiJCd5E4JxbwOuG6H2tbYI2Z-ajQXzzcodmCAWfWu2oRkMaAuNImph8W9tRrqCQ0wlb55tXnUvEuw",
    "expires_in": 300,
    "refresh_expires_in": 1800,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlYWQyMDZmOS05MzczLTQ1OTAtOGQ4OC03YWNkYmZjYTU5MmMifQ.eyJleHAiOjE1OTIzNDU0NDEsImlhdCI6MTU5MjM0MzY0MSwianRpIjoiOGE2NTdhMDktYTQ3My00OTAyLTk1MjItYWYxMGFkMzUwYzUyIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL2FwcHNkZXZlbG9wZXJibG9nIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL2FwcHNkZXZlbG9wZXJibG9nIiwic3ViIjoiMWRkZTNmYzMtYzZkYi00OWZiLTliM2QtNzk2NGM1YzA2ODdhIiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InBob3RvLWFwcC1jb2RlLWZsb3ctY2xpZW50Iiwic2Vzc2lvbl9zdGF0ZSI6ImYxMDliYjg5LWNkMzQtNDM3NC1iMDg0LWMzYzFjZjJjOGEwYiIsInNjb3BlIjoicHJvZmlsZSJ9.WevUHYd7DV3Ft7mFJnM2iLlArotBvLlMfQxlcy0nig8",
    "token_type": "bearer",
    "not-before-policy": 0,
    "session_state": "f109bb89-cd34-4374-b084-c3c1cf2c8a0b",
    "scope": "blockchainid"
}

Within the access token, you will be able to extract user information.