This section explains login & authentication flow of a native-app-based application. Overall, the login process consists of 2 steps:
Authentication - Single SignOn.
- Get Access Token.
Step 2 is identical to the process used by a web-based application, but the first step is a bit different.
But before you can get started, the application must be registered, which would provide the following pieces of information:
|Name||Description||Value used in the examples below|
A URL uniquely representing your app - this was provided to you when you registered for the developer license.
|The URL of the Saxo Bank authentication & authorization server - this was provided to you when you registered|
|AppKey||The Application key identifying your application to Saxo Bank - this was provided to you when you registered||-|
|AppSecret||The Application "secret" identifying your application to Saxo Bank - this was provided to you when you registered||-|
Never expose your AppKey and AppSecret to the users of your app - read our recommendations on security regarding AppKey and AppSecret here.
Authentication - Single SignOn
Authorizing a native app against SSO requires app to embed a browser control, because login flow if necessary redirects request to relevant login-page which returns a response containing SAML token embedded in its HTML(which must then be read from the browser, by the app).
The first step in the authorization process, is sending a SAML Authentication request to SSO. This is a POST request, containing a Base64 encoded SAML request as shown below:
In above code block, these fields are of important relevance:
|Field||Description||line no. in example|
|ID||A unique ID - in above example it is guid preceded by "_"||1|
|IssueInstant||The Request time (UTC, ISO 8601 formatted)||1|
The URL of the authentication endpoint (where request is actually sent to)
Destination = AuthenticationUrl + "/AuthnRequest".
This is used for telling SSO that the application trying to log in is your native app, it must be set to your Application URL, as it identifies your app uniquely
|saml:Issuer (tag contents)||The URL of the page issuing the request - this is set to the Application URL to signal that your app is issuing the request||5|
SAML request, must be POSTed as SAMLRequest to the authentication endpoint which is AuthenticationUrl + "/AuthnRequest" (e.g.
https://sim.logonvalidation.net/AuthnRequest for the SIM environment). For more info on various environments, visit - Link.
Below is the code construct from example to generate the request SAML:
In the example app, this is sent using the
The POST request must be sent with
content-type: application/x-www-form-urlencoded, and the SAML-request itself must be Base64 encoded and then URLEncoded (this last step is normally done by a normal form-submission in a browser, but if you post the request using a method like
WebBrowser.Navigate() this must be done manually).
If the user is not already logged in to SSO, it will redirect the user agent to the login dialog (which is why the request should be sent from the browser itself, and not server-to-server). After the authentication is finished (whether it required the login dialog or not), SSO renders a page containing the SAML response embedded in the BODY tag.
The process of detecting the "end state" and retrieving the actual SAML Response requires looking at each page the browser control receives, and check for a META tag on the page to determine the application state. The tag looks like this:
The state we are specifically interested in is the one where:
If the service is not IDP, the login process has not reached the IDP yet, and the page can be safely ignored. When the authentication completes, the authenticated value becomes True and the state becomes "Token" which means that page contains embedded token. If it has state=Ok and authenticated=True it is typically a sign that your app was registered as a website instead of a native app, which can be resolved by contacting Saxo Bank to change your registration.
state=Token" page looks something like this (the token is a lot larger than the snippet shown here):
In such a case SAML response can be read directly from the
SSO_SAML2_TOKEN attribute on the
BODY element. The response is URLEncoded and Base64 encoded and after decoding contains the SAML Response which looks something like this:
This response contains info for verifying the validity of the response (and sender) and that of the intended "audience" (this should be your site) – but for the sake of requesting the token, it is the AuthorizationCode attribute value that is important because this is what we use in next step: Acquiring an Access Token.
The AuthorizationCode value node can be found using the XPath expression: "
Get Access Token
Having the authorization code in hand, we can now exchange this for an Access Token by sending POST request to authorization url which is AuthenticationUrl + "/token" (e.g. for simulation its
i.e. AuthenticationUrl + "/token" ).
The endpoint to this is
- The POST request takes the parameters
code=<the authorization code from SSO>
- The authorization header contains the application key and app secret that you receive from Saxo Bank upon registering you application. The "<appKey>:<appSecret>" pair is Base64 encoded and prefixed by "
The response from the token endpoint is a JSON object containing Access Token as well as a Refresh Token which is used for acquiring more tokens when the current one expires:
token_type) values are used for calling OpenApi, and should be placed in some kind of persistent storage, to avoid unnecessary re-authentication.
The refresh_token value is used for getting a replacement token when the existing one is expiring. "
expires_in" and "
refresh_token_expires_in" are integer values that contain the expiry intervals (in seconds) for token and refresh token respectably.
Using Access Token
When the client application needs to invoke an OpenApi service, the token & token type are combined and put into the Authorization headers like this:
Refresh Access Token
Since the Access Token has a limited lifespan, it needs to be refreshed at regular intervals. For the same, token response contains a refresh token that has a longer expiry than the token itself and that can be exchanged for a new token.
The request for a new token is made against the same endpoint that the original token request was made, the only difference to the original request is the payload of the request as can be seen in below snapshot:
In the payload of the refresh request, the
grant_type is set to
refresh_token and the actual refresh token is provided in a parameter named
refresh_token, but the rest of the request is exactly identical. It also needs appKey and appsecret to identify the application and the returned JSON structure is identical - so you get a new token and a new refresh token.
Authentication Sequence Diagram
Sequence diagram of login flow is shown below:
As shown in the sequence diagram above, the application flow is very similar to the Web Server application login flow. The only difference here is it assumes that the application has access to a system browser, or has a browser embedded as a web view. Installed application can keep client secret and key in the application code or can talk to a back end Server application for getting the access token. In case the application is storing the application secret and key in application code then its the responsibility of the application to take proper measure to ensure that nobody can spoof the app secret and key.