Skip to content
Introducing the next era of Duende IdentityServer. Read our CEO’s announcement

OIDC Client Automatic Mode

OpenID Connect (OIDC) is an identity layer on top of the OAuth 2.0 protocol. It allows clients to verify the identity of the end-user based on the authentication performed by an authorization server, as well as obtain basic profile information.

An essential part of the OIDC flow is the use of a browser to interact with the end-user and to obtain permissions to access protected resources.

In the OidcClient library, you can encapsulate the browser interaction by implementing the IBrowser interface. Using IBrowser helps create a reusable component for all OIDC interaction.

// Copyright (c) Duende Software. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace Duende.IdentityModel.OidcClient.Browser;
/// <summary>
/// Models a browser
/// </summary>
public interface IBrowser
{
/// <summary>
/// Invokes the browser.
/// </summary>
/// <param name="options">The options.</param>
/// <param name="cancellationToken">A token that can be used to cancel the request</param>
/// <returns></returns>
Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default);
}

The BrowserResult represents the result of the browser interaction, including any OIDC payloads that are returned from the authentication server.

// Copyright (c) Duende Software. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace Duende.IdentityModel.OidcClient.Browser;
/// <summary>
/// The result from a browser login.
/// </summary>
/// <seealso cref="Result" />
public class BrowserResult : Result
{
/// <summary>
/// Gets or sets the type of the result.
/// </summary>
/// <value>
/// The type of the result.
/// </value>
public BrowserResultType ResultType { get; set; }
/// <summary>
/// Gets or sets the response.
/// </summary>
/// <value>
/// The response.
/// </value>
public string Response { get; set; }
}

The BrowserResult class inherits from Result, which provides error handling properties:

  • IsError - Indicates whether the browser interaction resulted in an error
  • Error - The error code if an error occurred
  • ErrorDescription - A human-readable description of the error

For a simple example, the following code shows how to use the SystemBrowser to invoke a browser on the host desktop platform. The SystemBrowser is a naive implementation that uses the System.Diagnostics.Process class to start the system default browser.

var options = new OidcClientOptions
{
Authority = "https://demo.duendesoftware.com",
ClientId = "native",
RedirectUri = redirectUri,
Scope = "openid profile api",
Browser = new SystemBrowser()
};
var client = new OidcClient(options);

Once the IBrowser is configured, the LoginAsync method can be invoked to start the authentication flow.

var result = await client.LoginAsync();

You can customize the login behavior by passing a LoginRequest object to LoginAsync:

var result = await client.LoginAsync(new LoginRequest
{
BrowserDisplayMode = DisplayMode.Hidden,
BrowserTimeout = 30,
FrontChannelExtraParameters = new Parameters
{
{ "acr_values", "mfa" },
{ "login_hint", "user@example.com" }
}
});
PropertyTypeDescription
BrowserDisplayModeDisplayModeControls browser visibility (Visible or Hidden)
BrowserTimeoutintTimeout in seconds for the browser interaction
FrontChannelExtraParametersParametersExtra parameters for the authorization endpoint
BackChannelExtraParametersParametersExtra parameters for the token endpoint

Setting the Browser property reduces the need to process browser respones and to handle the BrowserResult directly. When using this automatic mode, the LoginAsync method will return a LoginResult which will contain a ClaimsPrincipal with the user’s claims along with the IdentityToken and AccessToken.

The LoginResult class inherits from Result (providing IsError, Error, ErrorDescription) and exposes the following properties:

PropertyTypeDescription
UserClaimsPrincipalThe authenticated user’s claims principal
AccessTokenstringThe access token for calling protected APIs
IdentityTokenstringThe identity token containing user claims
RefreshTokenstringThe refresh token (if requested via offline_access scope)
AccessTokenExpirationDateTimeOffsetWhen the access token expires
AuthenticationTimeDateTimeOffset?When the user authenticated at the IdP
RefreshTokenHandlerDelegatingHandlerPre-configured handler for automatic token refresh
TokenResponseTokenResponseThe raw token endpoint response
var result = await client.LoginAsync();
if (result.IsError)
{
Console.WriteLine($"Error: {result.Error} - {result.ErrorDescription}");
return;
}
// Access user claims
var name = result.User.FindFirst("name")?.Value;
Console.WriteLine($"Hello, {name}!");
// Use access token for API calls
var apiClient = new HttpClient();
apiClient.SetBearerToken(result.AccessToken);
// Or use the pre-configured refresh handler for automatic token refresh
var apiClientWithRefresh = new HttpClient(result.RefreshTokenHandler);