Callback URLs

For device link flows that use a callback URL (Web2App and App2App links), the callback URL handling is very important to achieve a secure and phishing-resistant flow.

IMPORTANT

If Web2App and App2App flows are used simultaneously, the initialCallbackUrl must be different for both flows, otherwise Web2App flows callbackUrl might wrongly end up in the RP app.

Web2App callback URL

For Web2App callback URLs, the following steps must be followed:

  1. The user initiates authentication or signing flow on RP website.

  2. RP website backend has to set a session cookie to the user’s browser. This cookie must be set as SameSite=Lax because later, the Smart-ID app will launch the callback URL using top-level navigation and the request type will be GET.

  3. RP website backend makes a request to RP API and in the initialCallbackUrl, attaches a random parameter as a query parameter which it also saves in the backend and associates it with the session. The objective is for every initialCallbackUrl in any session to be unique and unpredictable.

  4. RP website backend saves the BASE64URL encoded SHA-256 digest of sessionSecret as sessionSecretDigest for later use during verification of the callbackUrl.

  5. Once the user has signed (or rejected the transaction), they are redirected to the callback URL address of RP website and their browser will have the same session cookie. Some aspects to take into account are:

    • User will end up on a new browser tab;

    • The callback URL contains an additional parameter sessionSecretDigest which is the Base64URL encoded SHA-256 digest of the sessionSecret; and in case of authentication flows, it also contains the parameter userChallengeVerifier which is also Base64URL encoded.

  6. RP website sends the callback URL to RP website backend.

  7. RP website backend polls RP API /v3/session/{sessionID} endpoint for the session API response. Note that this can be done before or after the user has returned to the RP website via the callback URL.

  8. RP website backend performs the following checks:

    • Verify that the user’s session cookie matches with the random parameter attached in the callback URL;

    • Verify that the SHA-256 digest of the sessionSecret equals to sessionSecretDigest in the callback URL;

    • In authentication flows, verify that after applying the SHA-256 hash algorithm to userChallengeVerifier value (as is, without Base64URL decoding), the result equals to the userChallenge within the signature object sent by the RP API in the session API response;

    • Perform the response verification steps described in Response verification page. Note that this cannot be performed before the user has returned to the RP website via the callback URL;

    • Invalidate the old user session and generate a new one. callbackUrl must be invalidated after use and must not be accepted after it is used once. Failing to invalidate the callbackUrl after use may leave the user vulnerable to a phishing attack.

    • Redirect the user to a new page and show authenticated session.

IMPORTANT

If any of these steps fail to verify, deny the authentication or signature attempt.

Multiple browser challenges

In cases where user initiated the authentication/signing flow on a mobile browser that was not their default browser, the HTTPS callback URL will probably be opened in the default browser which will not have the session cookie and thus the verification must fail.

App2App callback URL

The protocol steps for handling App2App callback URLs are functionally the same as for Web2App; however, there are also some differences in the steps below due to fundamental differences between webpages and apps.

For App2App callback URLs, the following steps must be followed:

  1. The user initiates authentication or signing flow on RP app.

  2. RP app has to save a session identifier in the app’s storage.

  3. RP app backend makes a request to RP API and in the initialCallbackUrl, attaches a random parameter as a query parameter which it also saves in the backend and associates it with the session. The objective is for every initialCallbackUrl in any session to be unique and unpredictable.

  4. RP app backend saves the BASE64URL encoded SHA-256 digest of sessionSecret as sessionSecretDigest for later use during verification of the callbackUrl.

  5. Once the user has signed (or rejected the transaction), they are redirected to the callback URL, which will cause RP app to open (for this to work, RP app has to be configured to handle that domain and path of the URL).

  6. The callback URL contains an additional parameter sessionSecretDigest which is the Base64URL encoded SHA-256 digest of the sessionSecret; and in case of authentication flows, it also contains the parameter userChallengeVerifier which is also Base64URL encoded.

  7. RP app sends the callback URL together with the session identifier from storage to RP app backend.

  8. RP website backend polls RP API /v3/session/{sessionID} endpoint for the session API response. Note that this can be done before or after the user has returned to the RP website via the callback URL.

  9. RP app backend performs the following checks:

    • Verify that the user’s session identifier matches with the random parameter attached in the callback URL;

    • Verify that the SHA-256 digest of the sessionSecret equals to sessionSecretDigest in the callback URL;

    • In authentication flows, verify that after applying the SHA-256 hash algorithm to userChallengeVerifier value (as is, without Base64URL decoding), the result equals to the userChallenge within the signature object sent by the RP API in the session API response;

    • Perform the response verification steps described in Response verification page. Note that this cannot be performed before the user has returned to the RP website via the callback URL;

    • Invalidate the old user session and generate a new one. callbackUrl must be invalidated after use and must not be accepted after it is used once. Failing to invalidate the callbackUrl after use may leave the user vulnerable to a phishing attack.

IMPORTANT

If any of these steps fail to verify, deny the authentication or signature attempt.

Callback URLs in linked notification based flows

Linked notification based flows are used in cases where the certificate of the user is required before the digest to be signed can be generated. In these flows callbackUrl is required and it is supplied by the RP in the initial device link based certificate choice request. However, the callbackUrl is not immediately used after the certificate choice request, and is only used after the /v3/signature/notification/linked endpoint is called with the mandatory linkedSessionID parameter and the flow is completed.

Callback URL examples

If the initial callback URL provided by RP backend is:

https://rp.example.com/callback-url?value=RrKjjT4aggzu27YBddX1bQ

then in the authentication flow the full callback URL would be:

https://rp.example.com/callback-url?value=RrKjjT4aggzu27YBddX1bQ&sessionSecretDigest=U4CKK13H1XFiyBofev9asqrzIrY5_Gszi_nL_zDKkBc&userChallengeVerifier=XtPfaGa8JnGtYrJjboooUf0KfY9sMEHrWFpSQrsUv9c

In the signature and certificate-choice flows the full callback URL would be:

https://rp.example.com/callback-url?value=RrKjjT4aggzu27YBddX1bQ&sessionSecretDigest=U4CKK13H1XFiyBofev9asqrzIrY5_Gszi_nL_zDKkBc

Phishing resistance

For both Web2App and App2App callback URLs, the checks described above provide complete phishing resistance. Always prefer device link flows if possible.

For the response verification steps, see Response verification page.