Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/470 use new auth properties app and web #477

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
159 changes: 149 additions & 10 deletions docs/articles/bankid.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ The most common scenbario is to use Active Login for BankID auth/login, so most
+ [Event listeners](#event-listeners)
+ [Store data on auth completion](#store-data-on-auth-completion)
+ [Resolve the end user ip](#resolve-the-end-user-ip)
+ [Resolve the end user device data](#resolve-the-end-user-device-data)
+ [Resolve requirements on Auth request](#resolve-requirements-on-auth-request)
+ [Resolve user data on Auth request](#resolve-user-data-on-auth-request)
+ [Custom QR code generation](#custom-qr-code-generation)
Expand Down Expand Up @@ -968,14 +969,148 @@ services.RemoveAll(typeof(IBankIdResultStore));

### Resolve the end user ip

In some scenarios, like running behind a proxy, you might want to resolve the end user IP yourself and override the default implementaion.
In some scenarios, like running behind a proxy, you might want to resolve the end user IP yourself and override the default implementation.

Either register a class implementing `IBankIdEndUserIpResolver`:

```csharp
services.AddTransient<IBankIdEndUserIpResolver, EndUserIpResolver>();
```

---
### Device data

When initiating a flow with BankID, the objects "app" or "web" can be included in the request.
The information in these two objects differs, but including either of them allows BankID to
provide a better risk indication.

When using BankID, device information provides valuable metadata that enhances security and ensures a smoother user experience.
Including the **device type** (e.g., `APP` or `WEB`) helps BankID:
- **Evaluate risk** for each request.
- **Take automated actions** based on high-risk scenarios (if enabled).
- Provide **better insights** into the context of the request.

#### Configuring Device Data

Active Login has a default implementation of the User Device feature that uses a
web browser as the device type. You can customize the default implementation or create your own.

The following service interface must be implemented to use the User Device feature:
- `IBankIdEndUserDeviceDataResolverFactory`: Factory that provides the resolvers for the device type.
- `IBankIdEndUserDeviceDataResolver`: Resolver that provides the device data for a given device type.
- `IBankIdEndUserDeviceDataConfiguration`: Configuration that specifies the device type to use.

#### What is included in the requests?

| Device Type | Default Resolver Implementation | Metadata Included |
|---------------|-------------------------------------------|--------------------------------------------|
| **Web** | `BankIdDefaultEndUserWebDeviceDataResolver` | Referring domain, User-Agent, DeviceIdentifier |
| **App** | `BankIdDefaultEndUserAppDeviceDataResolver` | App Identifier, Device OS, Model, DeviceIdentifier |

The Device identifier must be identical between requests.

The `BankIdDefaultEndUserWebDeviceDataResolver` will set a protected cookie named `__ActiveLogin.BankIdDeviceData` that contains
unique identifier (DeviceIdentifier) to ensure that the identifier is persistent across requests.

#### Customizing the User Device feature
To customize the User Device feature, use the `UseDeviceData` extension in the BankID client builder.
This allows you to specify the device type and any relevant metadata using resolvers.

The BankIdFlowService will automatically include the device data in the BankID request,
since it is dependent of the `IBankIdEndUserDeviceDataResolverFactory` service.

##### Configuration examples

If no configuration of the UseDeviceData has been set, the default implementation will be used.
This implementation will set the device type to `BankIdEndUserDeviceType.Web` and use
the `BankIdDefaultEndUserDeviceDataResolverFactory` to find the correct resolver for the device type.
The `BankIdDefaultEndUserWebDeviceDataResolver` is used to fetch the web browser information.

*If no custom implementation is made the device data defaults to this:*
```csharp
services
.AddBankId(bankId =>
{
bankId.UseDeviceData(config =>
{
// Set the device type for the request
config.DeviceType = BankIdEndUserDeviceType.Web;

// Use the default resolver factory
config.UseResolverFactory<BankIdDefaultEndUserDeviceDataResolverFactory>();

// Add the default resolver for Web
config.AddDeviceResolver<BankIdDefaultEndUserWebDeviceDataResolver>();
});
});
```

*Custom implementation requests initiated by av web browser:*
```csharp
services
.AddBankId(bankId =>
{
bankId.UseDeviceData(config =>
{
// Set the device type for the request
config.DeviceType = BankIdEndUserDeviceType.Web;

// Use a custom resolver factory
// that implements IBankIdEndUserDeviceDataResolverFactory
config.UseResolverFactory<MyCustomResolverFactory>();

// Add a custom resolver for the device type Web
// that implements IBankIdEndUserDeviceDataResolver
config.AddDeviceResolver<MyCustomWebDeviceDataResolver>();
});
});
```


*Custom implementation requests initiated by a mobile app:*

```csharp
services
.AddBankId(bankId =>
{
bankId.UseDeviceData(config =>
{
// Set the device type starting the request
config.DeviceType = BankIdEndUserDeviceType.App;

// Use the default resolver factory to find what device data resolvers to use
config.UseResolverFactory<BankIdDefaultEndUserDeviceDataResolverFactory>();

// Use the default data resolver for the device type app
// On app devices (e.g. MAUI, Xamarin, etc.) we need to set the
// device data manually at start
config.AddDeviceResolver(s => new BankIdDefaultEndUserAppDeviceDataResolver()
{
// App ID or package name
AppIdentifier = "com.example.app",

// Device operating system
DeviceOs = "iOS 16.7.7",

// Device model
DeviceModelName = "Apple iPhone14,3",

// Unique hardware ID
DeviceIdentifier = "1234567890"
});

});
});
```
The information for the BankIdDefaultEndUserAppDeviceDataResolver has to be set during startup.

#### More information available at:
- [BankID Risk Indication](https://www.bankid.com/en/foretag/the-service/risk-indication)
- [BankID Api - Auth](https://developers.bankid.com/api-references/auth--sign/auth)
- [BankID Api - Sign](https://developers.bankid.com/api-references/auth--sign/sign)
- [BankID Api - Payment](https://developers.bankid.com/api-references/auth--sign/payment)

---
### Resolve requirements on Auth request

If you want to set the requirements on how the authentication order must be performed dynamically for each order instead of statically during startup in `Program.cs`, it can be done by overriding the default implementation of the `IBankIdAuthRequestRequirementsResolver`.
Expand Down Expand Up @@ -1290,15 +1425,19 @@ We have choosen not to normalize the capitalization of the names as it´s hard o

The `*.AspNetCore` package will issue a cookie to make the auth flow work

The cookie is called: `__ActiveLogin.BankIdUiState`

The cookie is there to store state during the auth process, as the user will/might be redirected during the flow. The cookie is session based only and will be deleted once the auth process is finished and/or when the user closes the browser.

Because it is strictly related to temp storage during auth, you should not have to inform the user about these specific cookies (according to the [EU "cookie law"](https://www.cookielaw.org/the-cookie-law/)).

With the current implementaiton (following the convention from Microsoft ASP.NET) the usage of cookies is not optional.

A more technical deep dive of the cookies can be found in [this issue](https://github.com/ActiveLogin/ActiveLogin.Authentication/issues/156).
- Cookie: `__ActiveLogin.BankIdUiState`
- This cookie is there to store state during the auth process, as the user will/might be redirected during the flow. The cookie is session based only and will be deleted once the auth process is finished and/or when the user closes the browser.

- Because it is strictly related to temp storage during auth, you should not have to inform the user about these specific cookies (according to the [EU "cookie law"](https://www.cookielaw.org/the-cookie-law/)).

- With the current implementation (following the convention from Microsoft ASP.NET) the usage of cookies is not optional.

- A more technical deep dive of this cookie can be found in [this issue](https://github.com/ActiveLogin/ActiveLogin.Authentication/issues/156).

- Cookie: `__ActiveLogin.BankIdDeviceData`
- This cookie is used to store the device data for the user, in the default implementation,
It is used to ensure that the device data is persistent across requests.



### Browser support
Expand Down
12 changes: 11 additions & 1 deletion samples/Standalone.MvcSample/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
using ActiveLogin.Authentication.BankId.AspNetCore;
using ActiveLogin.Authentication.BankId.AspNetCore.Auth;
using ActiveLogin.Authentication.BankId.AspNetCore.Sign;
using ActiveLogin.Authentication.BankId.AspNetCore.UserContext.Device.Resolvers;
using ActiveLogin.Authentication.BankId.AzureKeyVault;
using ActiveLogin.Authentication.BankId.AzureMonitor;
using ActiveLogin.Authentication.BankId.Core;
using ActiveLogin.Authentication.BankId.Core.CertificatePolicies;
using ActiveLogin.Authentication.BankId.Core.UserContext.Device;
using ActiveLogin.Authentication.BankId.Core.UserContext.Device.Configuration;
using ActiveLogin.Authentication.BankId.Core.UserContext.Device.ResolverFactory;
using ActiveLogin.Authentication.BankId.QrCoder;
using ActiveLogin.Authentication.BankId.UaParser;

Expand Down Expand Up @@ -62,6 +65,13 @@
options.LogDeviceUniqueHardwareId = false;
});

bankId.UseDeviceData(config =>
{
config.DeviceType = BankIdEndUserDeviceType.Web;
config.UseResolverFactory<BankIdDefaultEndUserDeviceDataResolverFactory>();
config.UseDeviceResolver<BankIdDefaultEndUserWebDeviceDataResolver>();
});

bankId.UseQrCoderQrCodeGenerator();
bankId.UseUaParserDeviceDetection();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace ActiveLogin.Authentication.BankId.Api;
public interface IBankIdEndUserDeviceData
{ }
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,25 @@ public class AuthRequest : Request
/// </param>
/// <param name="returnUrl">The URL to return to when the authentication order is completed.</param>
/// <param name="returnRisk">If set to true, a risk indication will be included in the collect response.</param>
/// <param name="deviceParameters">Information about the device the end user is using.</param>
public AuthRequest(
string endUserIp,
Requirement? requirement = null,
string? userVisibleData = null,
byte[]? userNonVisibleData = null,
string? userVisibleDataFormat = null,
string? returnUrl = null,
bool? returnRisk = null)
bool? returnRisk = null,
IBankIdEndUserDeviceData? deviceParameters = null)
: base(
endUserIp,
userVisibleData: userVisibleData,
userNonVisibleData: userNonVisibleData,
requirement: requirement,
userVisibleDataFormat: userVisibleDataFormat,
returnUrl: returnUrl,
returnRisk: returnRisk
returnRisk: returnRisk,
deviceParameters: deviceParameters
)
{
}
Expand Down
25 changes: 25 additions & 0 deletions src/ActiveLogin.Authentication.BankId.Api/Models/DeviceData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace ActiveLogin.Authentication.BankId.Api.Models;

/// <summary>
/// Base class for device parameters.
/// </summary>
/// <param name="deviceIdentifier">
/// The identifier of the device your client is running on.
/// This is used to uniquely identify the device and should be a value
/// that is not tied to a single user of the device.
/// Preferably, it should remain the same even if your app is reinstalled.
/// </param>
public abstract class DeviceData(string deviceIdentifier) : IBankIdEndUserDeviceData
{
/// The identifier of the device your client is running on.
/// This is used to uniquely identify the device and should be a value
/// that is not tied to a single user of the device.
/// Preferably, it should remain the same even if your app is reinstalled.
[JsonPropertyName("deviceIdentifier")]
public string? DeviceIdentifier { get; } = deviceIdentifier;

}

50 changes: 50 additions & 0 deletions src/ActiveLogin.Authentication.BankId.Api/Models/DeviceDataApp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Text.Json.Serialization;

namespace ActiveLogin.Authentication.BankId.Api.Models;

/// <summary>
/// Parameters for the device where the BankID app is running.
/// </summary>
/// <param name="appIdentifier">
/// The identifier of your application.
/// This is the package name on Android and the bundle identifier on iOS.
/// It is vital to use the correct value.If your service does not supply the correct value legitimate orders might be blocked.</param>
/// E.g. "com.example.myapp"
/// <param name="deviceOs">
/// The device operating system where your app is running.
/// E.g. "IOS 16.7.7"
/// </param>
/// <param name="deviceModelName">
/// The model of the device your app is running on.
/// E.g. "Apple iPhone14,3"
/// </param>
/// <param name="deviceIdentifier">
/// <inheritdoc cref="DeviceData(string)" path="/param[@name='deviceIdentifier']"/>
/// </param>
public sealed class DeviceDataApp(
string appIdentifier,
string deviceOs,
string deviceModelName,
string deviceIdentifier)
: DeviceData(deviceIdentifier)
{
/// <summary>
/// Application Identifier, e.g. package name on Android and the bundle identifier on iOS.
/// </summary>
[JsonPropertyName("appIdentifier")]
public string? AppIdentifier { get; set; } = appIdentifier;

/// <summary>
/// Device operating system.
/// </summary>
[JsonPropertyName("deviceOS")]
public string? DeviceOs { get; set; } = deviceOs;

/// <summary>
/// Device model
/// </summary>
[JsonPropertyName("deviceModelName")]
public string? DeviceModelName { get; set; } = deviceModelName;

}

39 changes: 39 additions & 0 deletions src/ActiveLogin.Authentication.BankId.Api/Models/DeviceDataWeb.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Text.Json.Serialization;

namespace ActiveLogin.Authentication.BankId.Api.Models;

/// <summary>
/// Parameters for the browser where the BankID app is running.
/// </summary>
/// <param name="referringDomain">
/// The domain that starts the BankID app.
/// This should generally be your domain name followed by the public suffix,
/// which will generally be the top level domain.
/// E.g. "example.com"
/// </param>
/// <param name="userAgent">
/// The user agent of the user interacting with your web page.
/// E.g. "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/114.0"
/// </param>
/// <param name="deviceIdentifier">
/// <inheritdoc cref="DeviceData(string)" path="/param[@name='deviceIdentifier']"/>
/// </param>
public sealed class DeviceDataWeb(
string referringDomain,
string userAgent,
string deviceIdentifier)
: DeviceData(deviceIdentifier)
{
/// <summary>
/// The domain that starts the BankID app.
/// </summary>
[JsonPropertyName("referringDomain")]
public string? ReferringDomain { get; set; } = referringDomain;

/// <summary>
/// The user agent of the user interacting with your web page.
/// </summary>
[JsonPropertyName("userAgent")]
public string? UserAgent { get; set; } = userAgent;

}
Loading
Loading