#### [Abblix\.Oidc\.Server](https://www.abblix.com/docs/api/abblix-oidc-server 'index')
### [Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.Interfaces](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces 'Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.Interfaces')

## IUserDeviceAuthenticationHandler Interface

Defines the contract for initiating user authentication on a device in the context of a backchannel authentication
flow\. This interface is responsible for handling the initiation of the authentication process for the end\-user
on their device, based on a validated backchannel authentication request\.

```csharp
public interface IUserDeviceAuthenticationHandler
```

### Remarks

<strong>Implementation Guide:</strong>

Implement this interface to integrate your authentication mechanism with CIBA. Your implementation should:
- Send authentication request to user's device (push notification, SMS, email, etc.)
- Display binding_message if present in the request
- Handle user approval/denial asynchronously
- Update authentication status when user responds

<strong>Example Implementation with Ping Mode Support:</strong>

```csharp
public class MyUserDeviceAuthenticationHandler : IUserDeviceAuthenticationHandler
{
    private readonly IBackChannelRequestStorage _storage;
    private readonly IAuthenticationCompletionHandler _completion;
    private readonly ISessionIdGenerator _sessionIdGenerator;
    private readonly IMyPushNotificationService _pushService;
    private readonly IBackChannelLongPollingService? _longPolling;

    public async Task<Result<AuthSession, OidcError>> InitiateAuthenticationAsync(
        ValidBackChannelAuthenticationRequest request)
    {
        // Extract user hint and send authentication request to their device
        var userIdentifier = ExtractUserIdentifier(request);
        var bindingMessage = request.Model.BindingMessage;

        // Send push notification to user's device
        await _pushService.SendAuthRequestAsync(userIdentifier, bindingMessage);

        // Return pending - authentication completes asynchronously
        // User will approve/deny on their device
        return new OidcError(ErrorCodes.AuthorizationPending, "Waiting for user approval");
    }

    // Called when user approves on their device
    public async Task OnUserApprovedAsync(string authReqId, string userId)
    {
        // Retrieve the stored authentication request
        var storedRequest = await _storage.TryGetAsync(authReqId);
        if (storedRequest == null) return;

        // Create authenticated session
        var authSession = new AuthSession(
            userId,
            SessionId: _sessionIdGenerator.GenerateSessionId(),
            AuthenticationTime: DateTimeOffset.UtcNow,
            IdentityProvider: "local");

        // Carry the end user's answer on the grant. AuthorizedGrant is a positional member of the
        // record, so it is init-only and a `with` expression is how it is replaced; the copy carries
        // every other member unchanged.
        //
        // Nothing needs to touch Status ON THIS PATH - the denial below is a different one, and it
        // never calls CompleteAsync. A host that does set it on its own copy changes nothing
        // either way: completion reads the STORED record and writes whatever it decides itself.
        var authenticated = storedRequest with
        {
            AuthorizedGrant = new AuthorizedGrant(authSession, storedRequest.AuthorizedGrant.Context),
        };

        // Completion selects the mode-specific handler from the client's registered delivery mode
        // (PollModeCompletionHandler, PingModeCompletionHandler or PushModeCompletionHandler).
        await _completion.CompleteAsync(
            authReqId,
            authenticated,
            TimeSpan.FromMinutes(5));
    }

    // Called when user denies on their device
    public async Task OnUserDeniedAsync(string authReqId)
    {
        var storedRequest = await _storage.TryGetAsync(authReqId);
        if (storedRequest == null) return;

        storedRequest.Status = BackChannelAuthenticationStatus.Denied;
        await _storage.UpdateAsync(authReqId, storedRequest, TimeSpan.FromMinutes(5));

        // Writing the status is not telling anybody. A poll-mode client waiting on a long poll is
        // woken by IBackChannelLongPollingService, which nothing in the library calls for a status
        // the host wrote itself - so without this the user's refusal answers only when the waiter's
        // window runs out. Inject the notifier where the deployment registered one.
        if (_longPolling != null)
            await _longPolling.NotifyStatusChangeAsync(authReqId, storedRequest.Status);
    }
}
```

<strong>Token Delivery Modes:</strong>

The [CompleteAsync\(string, BackChannelAuthenticationRequest, TimeSpan\)](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.IAuthenticationCompletionHandler#Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.IAuthenticationCompletionHandler.CompleteAsync(string,Abblix.Oidc.Server.Features.BackChannelAuthentication.BackChannelAuthenticationRequest,System.TimeSpan) 'Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.Interfaces\.IAuthenticationCompletionHandler\.CompleteAsync\(string, Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.BackChannelAuthenticationRequest, System\.TimeSpan\)') method automatically handles
mode-specific behavior based on the client's registered `backchannel_token_delivery_mode`:
- <strong>Poll Mode:</strong> Stores the authenticated request in
                   [IBackChannelRequestStorage](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.IBackChannelRequestStorage 'Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.Interfaces\.IBackChannelRequestStorage'). No token exists yet - the client polls the token
                   endpoint with its `auth_req_id`, and the tokens are minted there when it redeems.
- <strong>Ping Mode:</strong> Stores the authenticated request as poll mode does, then sends an
                   HTTP POST notification via [INotificationDeliveryService](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.INotificationDeliveryService 'Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.Interfaces\.INotificationDeliveryService') to the client's
                   `client_notification_endpoint` carrying the `auth_req_id`. The tokens are minted at
                   the token endpoint when the client redeems, exactly as in poll mode.
- <strong>Push Mode:</strong> Generates tokens via [ITokenRequestProcessor](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Endpoints.Token.Interfaces.ITokenRequestProcessor 'Abblix\.Oidc\.Server\.Endpoints\.Token\.Interfaces\.ITokenRequestProcessor') and delivers
                   them directly via [INotificationDeliveryService](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.INotificationDeliveryService 'Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.Interfaces\.INotificationDeliveryService') to the client's
                   `client_notification_endpoint`. This is the only mode where the tokens exist before the
                   client asks for them, and the request is removed once they are delivered, because a push client
                   never comes to the token endpoint. CIBA Core 1.0 does not require that removal - it says nothing
                   about what the OP keeps - so it is this library's choice.

<strong>Partial consent (RFC 9396 authorization_details):</strong>

The grant carried on the stored request is what will be issued, so an end user who approved part of
what the client asked for is expressed by replacing its `AuthorizationContext` before completing:
keep the entries they agreed to, drop the ones they refused, and hand the result to
[CompleteAsync\(string, BackChannelAuthenticationRequest, TimeSpan\)](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.IAuthenticationCompletionHandler#Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.IAuthenticationCompletionHandler.CompleteAsync(string,Abblix.Oidc.Server.Features.BackChannelAuthentication.BackChannelAuthenticationRequest,System.TimeSpan) 'Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.Interfaces\.IAuthenticationCompletionHandler\.CompleteAsync\(string, Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.BackChannelAuthenticationRequest, System\.TimeSpan\)'). The example above copies the context
unchanged, which is the "they agreed to all of it" case.

This is the only moment such an answer exists. [InitiateAuthenticationAsync\(ValidBackChannelAuthenticationRequest\)](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.IUserDeviceAuthenticationHandler#Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.IUserDeviceAuthenticationHandler.InitiateAuthenticationAsync(Abblix.Oidc.Server.Endpoints.BackChannelAuthentication.Interfaces.ValidBackChannelAuthenticationRequest) 'Abblix\.Oidc\.Server\.Features\.BackChannelAuthentication\.Interfaces\.IUserDeviceAuthenticationHandler\.InitiateAuthenticationAsync\(Abblix\.Oidc\.Server\.Endpoints\.BackChannelAuthentication\.Interfaces\.ValidBackChannelAuthenticationRequest\)')
runs before the end user has seen anything - the session it returns names who is about to be reached,
and the request is stored pending either way - so there is nothing to narrow there.

Narrowing is yours to decide; widening is refused. Completion compares the grant's
`authorization_details` types against what the client actually sent, and a type the request never
carried denies the request rather than issuing it. RFC 9396 §7 has the server return what was granted,
which is only meaningful while "granted" stays inside "requested".

<strong>Additional Key Points:</strong>
- <strong>Binding Message:</strong> Display request.Model.BindingMessage to user for transaction confirmation
- <strong>User Code:</strong> If request.Model.UserCode is present, require user to confirm it
- <strong>Authentication:</strong> All notifications use Bearer token from `client_notification_token`

<strong>Security contract - user_code verification (CIBA Core 1.0 §7.1):</strong>

The library validates only the <em>presence</em> of `user_code` when the provider and client
require it (see [UserCodeValidator](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Endpoints.BackChannelAuthentication.Validation.UserCodeValidator 'Abblix\.Oidc\.Server\.Endpoints\.BackChannelAuthentication\.Validation\.UserCodeValidator')); it
deliberately does not - and cannot - verify the code's <em>value</em>, because the secret is known
only to the end-user and the user's authentication device, which this handler owns. Your
implementation therefore <strong>MUST</strong> verify `request.Model.UserCode` against the
user's actual code as part of the device interaction, and <strong>MUST NOT</strong> return a
successful [AuthSession](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Features.UserAuthentication.AuthSession 'Abblix\.Oidc\.Server\.Features\.UserAuthentication\.AuthSession') unless that check passed. A wrong or absent code MUST resolve
to a failed [Result&lt;TSuccess,TFailure&gt;](https://www.abblix.com/docs/api/abblix-utils/Abblix.Utils.Result_TSuccess_TFailure_ 'Abblix\.Utils\.Result\`2') (typically `access_denied`).
Treating presence-validation as sufficient leaves the code unenforced and defeats its purpose.
### Methods

## IUserDeviceAuthenticationHandler\.InitiateAuthenticationAsync\(ValidBackChannelAuthenticationRequest\) Method {#Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.IUserDeviceAuthenticationHandler.InitiateAuthenticationAsync(Abblix.Oidc.Server.Endpoints.BackChannelAuthentication.Interfaces.ValidBackChannelAuthenticationRequest)}

Initiates the authentication process for the user on their device, based on a validated backchannel
authentication request\.
This may involve sending a notification to the user's device, starting an out\-of\-band
authentication process, or performing other steps required to authenticate the user asynchronously\.

```csharp
System.Threading.Tasks.Task<Abblix.Utils.Result<Abblix.Oidc.Server.Features.UserAuthentication.AuthSession,Abblix.Oidc.Server.Common.OidcError>> InitiateAuthenticationAsync(Abblix.Oidc.Server.Endpoints.BackChannelAuthentication.Interfaces.ValidBackChannelAuthenticationRequest request);
```
#### Parameters

###### `request` [ValidBackChannelAuthenticationRequest](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Endpoints.BackChannelAuthentication.Interfaces.ValidBackChannelAuthenticationRequest 'Abblix\.Oidc\.Server\.Endpoints\.BackChannelAuthentication\.Interfaces\.ValidBackChannelAuthenticationRequest') {#Abblix.Oidc.Server.Features.BackChannelAuthentication.Interfaces.IUserDeviceAuthenticationHandler.InitiateAuthenticationAsync(Abblix.Oidc.Server.Endpoints.BackChannelAuthentication.Interfaces.ValidBackChannelAuthenticationRequest).request}

The validated backchannel authentication request containing user and client information
            required to initiate the authentication process\.

#### Returns
[System\.Threading\.Tasks\.Task&lt;](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1 'System\.Threading\.Tasks\.Task\`1')[Abblix\.Utils\.Result&lt;](https://www.abblix.com/docs/api/abblix-utils/Abblix.Utils.Result_TSuccess_TFailure_ 'Abblix\.Utils\.Result\`2')[AuthSession](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Features.UserAuthentication.AuthSession 'Abblix\.Oidc\.Server\.Features\.UserAuthentication\.AuthSession')[,](https://www.abblix.com/docs/api/abblix-utils/Abblix.Utils.Result_TSuccess_TFailure_ 'Abblix\.Utils\.Result\`2')[OidcError](https://www.abblix.com/docs/api/abblix-oidc-server/Abblix.Oidc.Server.Common.OidcError 'Abblix\.Oidc\.Server\.Common\.OidcError')[&gt;](https://www.abblix.com/docs/api/abblix-utils/Abblix.Utils.Result_TSuccess_TFailure_ 'Abblix\.Utils\.Result\`2')[&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task-1 'System\.Threading\.Tasks\.Task\`1')  
A [System\.Threading\.Tasks\.Task](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.task 'System\.Threading\.Tasks\.Task') representing the asynchronous operation to initiate the authentication process\.
