Skip to content

Commit 1226988

Browse files
authored
Add additional tooling for same device flows (#139)
* SLIB-126 - fix AuthenticationResponseValidator issue with authentication response started with initialCallbackUrl, but QR-code flow was used by user * SLIB-126 - add util to create callbackUrl with url-token * SLIB-126 - add util to create callbackUrl with url-token * SLIB-126 - improve comments * SLIB-126 - move UrlSafeTokenGenerator and CallbackUrl to common package * SLIB-126 - improve code style in CallbackUrlUtilTest
1 parent 22ea369 commit 1226988

16 files changed

Lines changed: 804 additions & 224 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
44

55
Changes mentioned under 3.1.x version have not been published yet. Will be released when v3.1 is stable.
66

7+
## [3.1.15] - 2025-09-17
8+
- Added CallbackUrlUtil to generate callback URL with token and provides method to validate sessionSecretDigest
9+
- Updated DeviceLinkAuthenticationResponseValidator to also validate userChallenge and userChallengeVerifier same device flows.
10+
711
## [3.1.14] - 2025-09-17
812
- Updated notification-based authentication session request creation to be usable with Smart-ID API v3.1
913
- Removed verificationCodeChoice interactions and related handling

README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ This library supports Smart-ID API v3.1.
4040
* [Generating QR-code](#generating-qr-code)
4141
* [Generate QR-code Data URI](#generate-qr-code-data-uri)
4242
* [Generate QR-code with custom height, width, quiet area and image format](#generate-qr-code-with-custom-height-width-quiet-area-and-image-format)
43+
* [Callback URL validation](#validating-callback-url)
4344
* [Querying sessions status](#session-status-request-handling-for-v31)
4445
* [Sessions status response](#session-status-response)
4546
* [Example of querying session status in v3.1](#examples-of-querying-session-status-in-v31)
@@ -330,6 +331,54 @@ Instant responseReceivedAt = authenticationSessionResponse.receivedAt();
330331
Jump to [Generate QR-code and device link](#generating-qr-code-or-device-link) to see how to generate QR-code or device link from the response.
331332
Jump to [Query session status](#example-of-using-session-status-poller-to-query-final-sessions-status) for an example of session querying.
332333

334+
335+
##### Initiating a device-link authentication session with document number for Web2App flow
336+
337+
```java
338+
String documentNumber = "PNOLT-40504040001-MOCK-Q";
339+
340+
// For security reasons a new rpChallenge must be created for each new authentication request
341+
RpChallenge rpChallenge = RpChallengeGenerator.generate();
342+
// Store generated rpChallenge only on backend side. Do not expose it to the client side.
343+
// Used for validating OK authentication sessions status response
344+
345+
// Generate callback URL to be used for same device flows(Web2App, App2App)
346+
CallbackUrl callbackUrl = CallbackUrlUtil.createCallbackUrl("your-app://callback");
347+
348+
DeviceLinkAuthenticationSessionRequestBuilder builder = smartIdClient
349+
.createDeviceLinkAuthentication()
350+
.withDocumentNumber(documentNumber)
351+
.withRpChallenge(rpChallenge.toBase64EncodedValue())
352+
.withInteractions(Collections.singletonList(
353+
DeviceLinkInteraction.displayTextAndPin("Logging into <app-name>") // Display text should be concise and specific.
354+
))
355+
.withInitialCallbackUrl(callbackUrl.initialCallbackUri().toString()); // Set initial callback URL in the session request
356+
357+
// Initiate authentication session
358+
DeviceLinkSessionResponse authenticationSessionResponse = builder.initAuthenticationSession();
359+
360+
// Get authentication session request used for starting the authentication session and use it later to validate sessions status response
361+
AuthenticationSessionRequest authenticationSessionRequest = builder.getAuthenticationSessionRequest();
362+
363+
// Use sessionID to start polling for session status
364+
String sessionId = authenticationSessionResponse.sessionID();
365+
366+
// Following values are used for generating device link or QR-code
367+
String sessionToken = authenticationSessionResponse.sessionToken();
368+
// Store sessionSecret only on backend side. Do not expose it to the client side.
369+
String sessionSecret = authenticationSessionResponse.sessionSecret();
370+
URI deviceLinkBase = authenticationSessionResponse.deviceLinkBase();
371+
// Will be used to calculate elapsed time being used in QR-code
372+
Instant responseReceivedAt = authenticationSessionResponse.receivedAt();
373+
374+
// Next steps:
375+
// - Generate QR-code or device link to be displayed to the user
376+
// - Start querying sessions status
377+
```
378+
Jump to [Generate QR-code and device link](#generating-qr-code-or-device-link) to see how to generate QR-code or device link from the response.
379+
Jump to [Query session status](#example-of-using-session-status-poller-to-query-final-sessions-status) for an example of session querying.
380+
Jump to [Validate callback URL](#validating-callback-url) for more info about validating callback URL.
381+
333382
### Device-link signature session
334383

335384
#### Request Parameters
@@ -632,6 +681,23 @@ BufferedImage qrCodeBufferedImage = QrCodeGenerator.generateImage(deviceLink.toS
632681
// Return Data URI to frontend and display the QR-code
633682
String qrCodeDataUri = QrCodeGenerator.convertToDataUri(qrCodeBufferedImage, "png");
634683
```
684+
### Validating callback URL
685+
686+
When using same device flows (Web2App or App2App) the initialCallbackUrl will be used by the Smart-ID app to redirect the user back to the Relying Party application.
687+
Received callback URL will contain additional query parameters that must be validated by the Relying Party.
688+
689+
Example of received callback URL for authentication:
690+
`https://rp.example.com/callback-url?value=RrKjjT4aggzu27YBddX1bQ&sessionSecretDigest=U4CKK13H1XFiyBofev9asqrzIrY5_Gszi_nL_zDKkBc&userChallengeVerifier=XtPfaGa8JnGtYrJjboooUf0KfY9sMEHrWFpSQrsUv9c`
691+
692+
Example of received callback URL for signature or certificate choice
693+
`https://rp.example.com/callback-url?value=RrKjjT4aggzu27YBddX1bQ&sessionSecretDigest=U4CKK13H1XFiyBofev9asqrzIrY5_Gszi_nL_zDKkBc`
694+
695+
1. RP must verify that the user sessions has `callbackUrl.urlToken()` with same value as in query parameter `value`.
696+
2. RP must verify that the `sessionSecretDigest` query parameter matches the calculated digest created from session secret received in device link session init response.
697+
For this library provides `CallbackUrlUtil.validateSessionSecretDigest(digestFromCallbackUrl, sessionSecret)`
698+
3. For authentication same device flow RP also must verify the `userChallengeVerifier` query parameter. This can be done when polling the session status has finished and session status response has to be
699+
validated. `deviceLinkAuthenticationResponseValidator.validate(sessionStatus, authenticationSessionRequest, userChallengeVerifier, schemaName, brokeredRpName);`
700+
Value to validate `userChallengeVerifier` is in the session status response `signature.userChallenge`.
635701

636702
## Session status request handling for v3.1
637703

src/main/java/ee/sk/smartid/AuthenticationResponseValidator.java

Lines changed: 0 additions & 169 deletions
This file was deleted.

0 commit comments

Comments
 (0)