Skip to content

Commit 500e521

Browse files
ZonnexElin Fokine
andauthored
feat(#479): Send returnUrl to BankID as part of the auth/sign/payment requests
* feat(#479): Send returnUrl to BankID as part of the auth/sign/payment requests * Use existing logic in active login to provide the correct return url depending on device, os, etc. This logic is currently used when setting the return url as part of the auto launch url and should be applied when sending the return url to bankid as part of the auth, sign or payment request as well. --------- Co-authored-by: Elin Fokine <ElinO@activesolution.se>
1 parent 969d25c commit 500e521

10 files changed

Lines changed: 139 additions & 35 deletions

File tree

src/ActiveLogin.Authentication.BankId.Api/BankIdAppApiClientExtensions.cs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace ActiveLogin.Authentication.BankId.Api;
66
/// Extensions to enable easier access to common api scenarios.
77
/// </summary>
88
public static class BankIdAppApiClientExtensions
9-
{
9+
{
1010
/// <summary></summary>
1111
/// <param name="appApiClient">The <see cref="IBankIdAppApiClient"/> instance.</param>
1212
/// <param name="endUserIp">
@@ -27,21 +27,26 @@ public static class BankIdAppApiClientExtensions
2727
/// <param name="userVisibleDataFormat">
2828
/// If present, and set to "simpleMarkdownV1", this parameter indicates that userVisibleData holds formatting characters which, if used correctly, will make the text displayed with the user nicer to look at.
2929
/// For further information of formatting options, please study the document Guidelines for Formatted Text.
30+
/// </param>
31+
/// <param name="returnUrl">
32+
/// If present the user will be redirected to this URL when the order is completed. Any return URL provided in the start URL when the BankID app was launched will be ignored.
3033
/// </param>
3134
public static Task<AuthResponse> AuthAsync(
3235
this IBankIdAppApiClient appApiClient,
3336
string endUserIp,
3437
Requirement? requirement = null,
3538
string? userVisibleData = null,
3639
byte[]? userNonVisibleData = null,
37-
string? userVisibleDataFormat = null)
40+
string? userVisibleDataFormat = null,
41+
string? returnUrl = null)
3842
{
3943
return appApiClient.AuthAsync(new(
4044
endUserIp,
4145
userVisibleData: userVisibleData,
4246
userNonVisibleData: userNonVisibleData,
4347
requirement: requirement,
44-
userVisibleDataFormat: userVisibleDataFormat));
48+
userVisibleDataFormat: userVisibleDataFormat,
49+
returnUrl: returnUrl));
4550
}
4651

4752
/// <summary>
@@ -81,8 +86,8 @@ public static Task<AuthResponse> AuthAsync(this IBankIdAppApiClient appApiClient
8186
public static Task<SignResponse> SignAsync(this IBankIdAppApiClient appApiClient, string endUserIp, string userVisibleData)
8287
{
8388
return appApiClient.SignAsync(new SignRequest(endUserIp, userVisibleData));
84-
}
85-
89+
}
90+
8691
/// <summary>
8792
/// Initiates an authentication order. Use the collect method to query the status of the order.
8893
/// </summary>
@@ -100,14 +105,18 @@ public static Task<SignResponse> SignAsync(this IBankIdAppApiClient appApiClient
100105
/// </param>
101106
/// <param name="userNonVisibleData">
102107
/// Data not displayed to the user.
108+
/// </param>
109+
/// <param name="returnUrl">
110+
/// If present the user will be redirected to this URL when the order is completed. Any return URL provided in the start URL when the BankID app was launched will be ignored.
103111
/// </param>
104112
/// <returns>If the request is successful, the OrderRef and AutoStartToken is returned.</returns>
105-
public static Task<SignResponse> SignAsync(this IBankIdAppApiClient appApiClient, string endUserIp, string userVisibleData, byte[] userNonVisibleData)
113+
public static Task<SignResponse> SignAsync(this IBankIdAppApiClient appApiClient, string endUserIp, string userVisibleData, byte[] userNonVisibleData, string? returnUrl = null)
106114
{
107115
return appApiClient.SignAsync(new SignRequest(
108116
endUserIp,
109117
userVisibleData,
110-
userNonVisibleData: userNonVisibleData));
118+
userNonVisibleData: userNonVisibleData,
119+
returnUrl: returnUrl));
111120
}
112121

113122
/// <summary></summary>

src/ActiveLogin.Authentication.BankId.Api/Models/Request.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public Request(string endUserIp, string userVisibleData, byte[] userNonVisibleDa
4747
/// The user IP address as seen by RP. IPv4 and IPv6 is allowed.
4848
/// Note the importance of using the correct IP address.It must be the IP address representing the user agent (the end user device) as seen by the RP.
4949
/// If there is a proxy for inbound traffic, special considerations may need to be taken to get the correct address.
50-
///
50+
///
5151
/// In some use cases the IP address is not available, for instance for voice based services.
5252
/// In this case, the internal representation of those systems IP address is ok to use.
5353
/// </param>
@@ -71,7 +71,7 @@ public Request(string endUserIp, string userVisibleData, string userVisibleDataF
7171
/// The user IP address as seen by RP. IPv4 and IPv6 is allowed.
7272
/// Note the importance of using the correct IP address.It must be the IP address representing the user agent (the end user device) as seen by the RP.
7373
/// If there is a proxy for inbound traffic, special considerations may need to be taken to get the correct address.
74-
///
74+
///
7575
/// In some use cases the IP address is not available, for instance for voice based services.
7676
/// In this case, the internal representation of those systems IP address is ok to use.
7777
/// </param>
@@ -93,7 +93,7 @@ public Request(string endUserIp, string userVisibleData, byte[]? userNonVisibleD
9393
/// The user IP address as seen by RP. IPv4 and IPv6 is allowed.
9494
/// Note the importance of using the correct IP address.It must be the IP address representing the user agent (the end user device) as seen by the RP.
9595
/// If there is a proxy for inbound traffic, special considerations may need to be taken to get the correct address.
96-
///
96+
///
9797
/// In some use cases the IP address is not available, for instance for voice based services.
9898
/// In this case, the internal representation of those systems IP address is ok to use.
9999
/// </param>
@@ -141,7 +141,7 @@ public Request(string endUserIp, string? userVisibleData, byte[]? userNonVisible
141141
App = app;
142142

143143
RiskFlags = riskFlags;
144-
UserVisibleTransaction = userVisibleTransaction;
144+
UserVisibleTransaction = userVisibleTransaction;
145145
}
146146

147147
/// <summary>
@@ -189,7 +189,15 @@ public Request(string endUserIp, string? userVisibleData, byte[]? userNonVisible
189189
public string? UserNonVisibleData { get; }
190190

191191
/// <summary>
192-
/// Orders started on the same device (started with autostart token) will call this URL when the order is completed, ignoring any return URL provided in the start URL when the BankID app was launched.
192+
/// Orders started on the same device (started with autostart token) will call this URL when the order is completed,
193+
/// ignoring any return URL provided in the start URL when the BankID app was launched.
194+
///
195+
/// If the user has a version of the BankID app that does not support getting the returnUrl from the server,
196+
/// the order will be cancelled and the user will be asked to update their app.
197+
///
198+
/// The return URL you provide should include a nonce to the session.
199+
/// When the user returns to your app or web page, your service should verify that
200+
/// the device receiving the returnUrl is the same device that started the order.
193201
/// </summary>
194202
[JsonPropertyName("returnUrl"), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
195203
public string? ReturnUrl { get; set; }

src/ActiveLogin.Authentication.BankId.Api/Models/SignRequest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class SignRequest : Request
1010
/// The user IP address as seen by RP. IPv4 and IPv6 is allowed.
1111
/// Note the importance of using the correct IP address.It must be the IP address representing the user agent (the end user device) as seen by the RP.
1212
/// If there is a proxy for inbound traffic, special considerations may need to be taken to get the correct address.
13-
///
13+
///
1414
/// In some use cases the IP address is not available, for instance for voice based services.
1515
/// In this case, the internal representation of those systems IP address is ok to use.
1616
/// </param>

src/ActiveLogin.Authentication.BankId.AspNetCore/DataProtection/Serialization/BankIdUiStateSerializer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ protected override void Write(BinaryWriter writer, BankIdUiState model)
8080
writer.Write(paymentState.BankIdPaymentProperties.RiskWarning == null);
8181
writer.Write(paymentState.BankIdPaymentProperties.RiskWarning ?? string.Empty);
8282

83-
writer.Write(paymentState.BankIdPaymentProperties.RiskFlags == null);
83+
writer.Write(paymentState.BankIdPaymentProperties.RiskFlags == null);
8484
var riskFlagsStr = paymentState.BankIdPaymentProperties.RiskFlags != null ? string.Join(",", paymentState.BankIdPaymentProperties.RiskFlags.Select(r => r.ToString())) : string.Empty;
8585
writer.Write(riskFlagsStr);
8686

src/ActiveLogin.Authentication.BankId.Core/Flow/BankIdFlowService.cs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ IBankIdEndUserDeviceDataResolverFactory bankIdEndUserDeviceDataResolverFactory
6969
public async Task<BankIdFlowInitializeResult> InitializeAuth(BankIdFlowOptions flowOptions, string returnRedirectUrl)
7070
{
7171
var detectedUserDevice = _bankIdSupportedDeviceDetector.Detect();
72-
var response = await GetAuthResponse(flowOptions, detectedUserDevice);
72+
var returnUrl = await GetReturnUrl(flowOptions, returnRedirectUrl);
73+
74+
var response = await AuthAsync(flowOptions, detectedUserDevice, returnUrl);
7375

7476
await _bankIdEventTrigger.TriggerAsync(new BankIdInitializeSuccessEvent(personalIdentityNumber: null, response.OrderRef, detectedUserDevice, flowOptions));
7577

@@ -91,11 +93,11 @@ public async Task<BankIdFlowInitializeResult> InitializeAuth(BankIdFlowOptions f
9193
}
9294
}
9395

94-
private async Task<AuthResponse> GetAuthResponse(BankIdFlowOptions flowOptions, BankIdSupportedDevice detectedUserDevice)
96+
private async Task<AuthResponse> AuthAsync(BankIdFlowOptions flowOptions, BankIdSupportedDevice detectedUserDevice, string? returnUrl)
9597
{
9698
try
9799
{
98-
var request = await GetAuthRequest(flowOptions);
100+
var request = await GetAuthRequest(flowOptions, returnUrl);
99101
return await _bankIdAppApiClient.AuthAsync(request);
100102
}
101103
catch (BankIdApiException bankIdApiException)
@@ -105,7 +107,7 @@ private async Task<AuthResponse> GetAuthResponse(BankIdFlowOptions flowOptions,
105107
}
106108
}
107109

108-
private async Task<AuthRequest> GetAuthRequest(BankIdFlowOptions flowOptions)
110+
private async Task<AuthRequest> GetAuthRequest(BankIdFlowOptions flowOptions, string? returnUrl)
109111
{
110112
var endUserIp = _bankIdEndUserIpResolver.GetEndUserIp();
111113
var resolvedRequirements = await _bankIdAuthRequestRequirementsResolver.GetRequirementsAsync();
@@ -130,7 +132,7 @@ private async Task<AuthRequest> GetAuthRequest(BankIdFlowOptions flowOptions)
130132
userVisibleData: userData.UserVisibleData,
131133
userNonVisibleData: userData.UserNonVisibleData,
132134
userVisibleDataFormat: userData.UserVisibleDataFormat,
133-
returnUrl: null,
135+
returnUrl: returnUrl,
134136
returnRisk: returnRisk,
135137
web: webDeviceData,
136138
app: appDeviceData
@@ -140,7 +142,9 @@ private async Task<AuthRequest> GetAuthRequest(BankIdFlowOptions flowOptions)
140142
public async Task<BankIdFlowInitializeResult> InitializeSign(BankIdFlowOptions flowOptions, BankIdSignData bankIdSignData, string returnRedirectUrl)
141143
{
142144
var detectedUserDevice = _bankIdSupportedDeviceDetector.Detect();
143-
var response = await GetSignResponse(flowOptions, bankIdSignData, detectedUserDevice);
145+
var returnUrl = await GetReturnUrl(flowOptions, returnRedirectUrl);
146+
147+
var response = await SignAsync(flowOptions, bankIdSignData, detectedUserDevice, returnUrl);
144148

145149
await _bankIdEventTrigger.TriggerAsync(new BankIdInitializeSuccessEvent(personalIdentityNumber: null, response.OrderRef, detectedUserDevice, flowOptions));
146150

@@ -162,11 +166,11 @@ public async Task<BankIdFlowInitializeResult> InitializeSign(BankIdFlowOptions f
162166
}
163167
}
164168

165-
private async Task<SignResponse> GetSignResponse(BankIdFlowOptions flowOptions, BankIdSignData bankIdSignData, BankIdSupportedDevice detectedUserDevice)
169+
private async Task<SignResponse> SignAsync(BankIdFlowOptions flowOptions, BankIdSignData bankIdSignData, BankIdSupportedDevice detectedUserDevice, string? returnUrl)
166170
{
167171
try
168172
{
169-
var request = GetSignRequest(flowOptions, bankIdSignData);
173+
var request = GetSignRequest(flowOptions, bankIdSignData, returnUrl);
170174
return await _bankIdAppApiClient.SignAsync(request);
171175
}
172176
catch (BankIdApiException bankIdApiException)
@@ -176,11 +180,13 @@ private async Task<SignResponse> GetSignResponse(BankIdFlowOptions flowOptions,
176180
}
177181
}
178182

179-
private SignRequest GetSignRequest(BankIdFlowOptions flowOptions, BankIdSignData bankIdSignData)
183+
private SignRequest GetSignRequest(BankIdFlowOptions flowOptions, BankIdSignData bankIdSignData, string? returnUrl)
180184
{
181185
var endUserIp = _bankIdEndUserIpResolver.GetEndUserIp();
182186

183-
var certificatePolicies = bankIdSignData.CertificatePolicies.Any() ? bankIdSignData.CertificatePolicies: flowOptions.CertificatePolicies;
187+
var certificatePolicies = bankIdSignData.CertificatePolicies.Any()
188+
? bankIdSignData.CertificatePolicies
189+
: flowOptions.CertificatePolicies;
184190
var resolvedCertificatePolicies = GetResolvedCertificatePolicies(certificatePolicies, flowOptions.SameDevice);
185191

186192
var requiredPersonalIdentityNumber = bankIdSignData.RequiredPersonalIdentityNumber ?? flowOptions.RequiredPersonalIdentityNumber;
@@ -199,7 +205,7 @@ private SignRequest GetSignRequest(BankIdFlowOptions flowOptions, BankIdSignData
199205
userNonVisibleData: bankIdSignData.UserNonVisibleData,
200206
userVisibleDataFormat: bankIdSignData.UserVisibleDataFormat,
201207
requirement: requestRequirement,
202-
returnUrl: null,
208+
returnUrl: returnUrl,
203209
returnRisk: returnRisk,
204210
web: webDeviceData,
205211
app: appDeviceData
@@ -221,7 +227,9 @@ private SignRequest GetSignRequest(BankIdFlowOptions flowOptions, BankIdSignData
221227
public async Task<BankIdFlowInitializeResult> InitializePayment(BankIdFlowOptions flowOptions, BankIdPaymentData bankIdPaymentData, string returnRedirectUrl)
222228
{
223229
var detectedUserDevice = _bankIdSupportedDeviceDetector.Detect();
224-
var response = await GetPaymentResponse(flowOptions, bankIdPaymentData, detectedUserDevice);
230+
var returnUrl = await GetReturnUrl(flowOptions, returnRedirectUrl);
231+
232+
var response = await PaymentAsync(flowOptions, bankIdPaymentData, detectedUserDevice, returnUrl);
225233

226234
await _bankIdEventTrigger.TriggerAsync(new BankIdInitializeSuccessEvent(personalIdentityNumber: null, response.OrderRef, detectedUserDevice, flowOptions));
227235

@@ -243,11 +251,11 @@ public async Task<BankIdFlowInitializeResult> InitializePayment(BankIdFlowOption
243251
}
244252
}
245253

246-
private async Task<PaymentResponse> GetPaymentResponse(BankIdFlowOptions flowOptions, BankIdPaymentData bankIdPaymentData, BankIdSupportedDevice detectedUserDevice)
254+
private async Task<PaymentResponse> PaymentAsync(BankIdFlowOptions flowOptions, BankIdPaymentData bankIdPaymentData, BankIdSupportedDevice detectedUserDevice, string? returnUrl)
247255
{
248256
try
249257
{
250-
var request = GetPaymentRequest(flowOptions, bankIdPaymentData);
258+
var request = GetPaymentRequest(flowOptions, bankIdPaymentData, returnUrl);
251259
return await _bankIdAppApiClient.PaymentAsync(request);
252260
}
253261
catch (BankIdApiException bankIdApiException)
@@ -257,7 +265,7 @@ private async Task<PaymentResponse> GetPaymentResponse(BankIdFlowOptions flowOpt
257265
}
258266
}
259267

260-
private PaymentRequest GetPaymentRequest(BankIdFlowOptions flowOptions, BankIdPaymentData bankIdPaymentData)
268+
private PaymentRequest GetPaymentRequest(BankIdFlowOptions flowOptions, BankIdPaymentData bankIdPaymentData, string? returnUrl)
261269
{
262270
var endUserIp = _bankIdEndUserIpResolver.GetEndUserIp();
263271

@@ -291,7 +299,7 @@ private PaymentRequest GetPaymentRequest(BankIdFlowOptions flowOptions, BankIdPa
291299
userVisibleDataFormat: bankIdPaymentData.UserVisibleDataFormat,
292300
requirement: requestRequirement,
293301
returnRisk: returnRisk,
294-
returnUrl: null,
302+
returnUrl: returnUrl,
295303
riskFlags: riskFlags,
296304
app: appDeviceData,
297305
web: webDeviceData
@@ -323,6 +331,15 @@ private PaymentRequest GetPaymentRequest(BankIdFlowOptions flowOptions, BankIdPa
323331
return riskFlags.Select(x => x.ToString()).ToList();
324332
}
325333

334+
private async Task<string?> GetReturnUrl(BankIdFlowOptions flowOptions, string returnRedirectUrl)
335+
{
336+
if (!flowOptions.SameDevice) return null;
337+
338+
var launchUrlRequest = new LaunchUrlRequest(returnRedirectUrl, "");
339+
var launchInfo = await _bankIdLauncher.GetLaunchInfoAsync(launchUrlRequest);
340+
341+
return launchInfo.ReturnUrl;
342+
}
326343

327344
private Task<BankIdLaunchInfo> GetBankIdLaunchInfo(string redirectUrl, string autoStartToken)
328345
{

src/ActiveLogin.Authentication.BankId.Core/Launcher/BankIdDevelopmentLauncher.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@ namespace ActiveLogin.Authentication.BankId.Core.Launcher;
33
internal class BankIdDevelopmentLauncher : IBankIdLauncher
44
{
55
private const string DevelopmentLaunchUrl = "#";
6+
private const string DevelopmentReturnUrl = "";
67

78
public Task<BankIdLaunchInfo> GetLaunchInfoAsync(LaunchUrlRequest request)
89
{
910
// Always stay on same page, without reloading, in simulated mode
10-
return Task.FromResult(new BankIdLaunchInfo(DevelopmentLaunchUrl, false, false));
11+
return Task.FromResult(new BankIdLaunchInfo(DevelopmentLaunchUrl, false, false, DevelopmentReturnUrl));
1112
}
1213
}

0 commit comments

Comments
 (0)