- 05 Nov 2024
- 4 Minutes to read
- Print
- DarkLight
- PDF
Native Applications
- Updated on 05 Nov 2024
- 4 Minutes to read
- Print
- DarkLight
- PDF
Native applications are installed by users on their devices (mobile or desktop), thus these are different than Web applications that run only in browsers.
Because these apps run on users' devices, the current best practice is to use and external user-agent (Web browser) for performing the OAuth 2.0 authorization requests - it uses OAuth 2.0 Authorization Code Grant with Proof Key for Code Exchange (PKCE) extension recommended for public clients.
The Proof Key for Code Exchange (PKCE, pronounced pixie) extension describes a technique for public clients to mitigate the threat of having the authorization code intercepted. The technique involves the client first creating a secret, and then using that secret again when exchanging the authorization code for an access token. This way if the code is intercepted, it will not be useful since the token request relies on the initial secret.
Step 1: Authorization request
Before starting the authorization process, public applications create what is known as the code verifier. This is a cryptographically random string using the characters A-Z, a-z, 0-9, and the punctuation characters -._~ (hyphen, period, underscore, and tilde), between 43 and 128 characters long.
Once the app has generated the code verifier it uses that to create a code challenge. The code challenge is a BASE64-URL-encoded string of the SHA256 hash of the code verifier.
Now that the app has a code challenge, it includes that as parameter in the authorization request together with a parameter which indicates the method used to generate the challenge.
Name | Example Value | Required | Description |
---|---|---|---|
client_id | demoapp | yes | The Client ID set when application was registered. Identifies which app is making the request. |
response_type | code | yes | Determines whether the OAuth 2.0 endpoint returns an authorization code. Always set this to the code. |
scope | openid email profile offline_access visma_api:read The “visma_api:read” scope-name above is just an example - check your API documentation for scope(s) to use. | yes | Identifies the user information that your application is requesting. One scope openid is required. The values passed in this parameter inform the consent screen that is shown to the user. |
redirect_uri | myapp:/oauthcallback | yes | Determines where the OAuth Callback response is sent back to your application. The value of this parameter must exactly match the value added on application registration. Native applications can use custom scheme or localhost HTTP URIs. |
code_challenge | The code challenge generated | yes | Base64-URL-encoded string of SHA256 hash of the Code Verifier. |
code_challenge_method | S256 or plain | yes | Whether the challenge is the SHA256 hash of the string or the plain verifier string. |
state | This field can be a Base64 encoded JSON object that can hold multiple values | no | Authorization protocols provide a state parameter. During authentication, the application sends this parameter in the authorization request, and the Authorization Server will return this parameter unchanged in the response. Your application can use this parameter in order to make sure that the response belongs to a request that was initiated by the same user. Therefore, state helps mitigate CSRF attacks. Restore the previous state of your application. Read more |
response_mode | query | no | Specifies that the response parameters are returned to client in a query string. |
ui_locales | nb-NO sv-SE en-GB | no | End-User's preferred languages and scripts for the user interface, represented as a space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. Values currently supported:
|
tenant_hint | 604ad704-772a-46f7-8926-571769f067e7 | no | Tenant ID (context) for Applications doing authorization of user-roles as part of Visma Connect. |
Example:
GET https://connect.visma.com/connect/authorize?client_id=demoapp&response_type=code&response_mode=query&scope=openid+email+profile&redirect_uri=myapp:/oauthcallback&code_challenge=YOUR_CODE_CHALLENGE&code_challenge_method=S256&state=CfDJ8NbGuiMeKnBKlosjbaGWcBzxsyHJjSmlXdcP5HT0Jp_qH...tE8u1Ws&ui_locales=nb-NO+sv-SE+en-GB
Step 2: User consent
In this step, the user decides whether to grant your application the requested access or not. At this stage, Visma Connect displays a consent window with the name of your application seeking permission to access with the user’s authorization credentials. The user can then consent or refuse to grant access to your application.
Your application doesn’t need to do anything at this stage as it waits for the response from Visma Connect Authentication server indicating whether the access was granted or not.
Step 3: Authentication Response
Since the response mode for native applications is query, the authorization server sends the following response back to your application:
myApp:/oauthcallback?code=94c99b73c13c1e39f7b0a7d259628338&state=CfDJ8NbGuiMeKnBKlosjbaGWcBzxsyHJjSmlXdcP5HT0Jp_qH...tE8u1Ws
Step 4: Exchange Authorization Code for Tokens
After the app receives the authorization response, it exchanges the code for an Access Token and ID Token. The token request must include the code verifier parameter that was generated by your app before starting the authorization process. Sample request:
curl --request POST --url https://connect.visma.com/connect/token --header 'content-type: application/x-www-form-urlencoded' --data 'grant_type=authorization_code&redirect_uri=myApp%3A%2F/oauthcallbac&code=94c99b73c13c1e39f7b0a7d259628338&client_id=demoapp&code_verifier=YOUR_CODE_VERIFIER'
Name | Example Value | Required | Description |
---|---|---|---|
grant_type | authorization_code | yes | As defined in the OAuth 2.0 specification, this field must contain a value of authorization_code. |
redirect_uri | https://demoapp.example.com/oauthcallback | yes | The same value used on the authorization request. |
code | 94c99b73c13c1e39f7b0a7d259628338 | yes | The authentication code returned from the initial request |
client_id | demoapp | yes | The Client ID set when application was registered. Identifies which app is making the request. |
client_secret | The secret obtained when registering the application | yes | This is your application's Client Secret. |
code_verifier | The generated verifier | yes, when PKCE enabled | The code verifier for the PKCE request, that the app originally generated before the authorization request. |
If successful, this call will return a neatly packaged token that will contain the following fields:
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjVENDc....7MTOBbdd5mgb2CHzxL0RFjs24pqC1pCeUqOjbg",
"id_token": "eyJhbG....dsaeKOJdIHS988MLKJdsaCeUqOjbg",
"expires_in": 3600,
"token_type": "Bearer",
"scope": "openid email profile"
}
OAuth/OIDC library: Token verification and time on user device
Note that if your OAuth/OIDC library use the local time of the device for Token-verification, then you rely on the end-users device clock to be accurate in order for the Token-verification to succeed.
When Identity Scopes are used in the authentication request your application can retrieve additional information about the authenticated user from UserInfo Endpoint.