Web providers client
IMPORTANT
This page focuses on configuring the OpenIddict client to use an existing provider. For more information on how to contribute a new provider that is not yet supported by OpenIddict, read Contributing a new Web provider.
To simplify integrating with well-known OAuth 2.0 or OpenID Connect providers, the OpenIddict client ships with a companion package named OpenIddict.Client.WebIntegration
that supports 90+ popular services like Amazon, Discord, GitHub, Microsoft or Sign in with Apple.
TIP
The OpenIddict client and its web providers can be used independently of the OpenIddict server feature.
Supported platforms
All the providers included in this package can be used in any web application – ASP.NET 4.6.1+ or ASP.NET Core 2.1+ – and any desktop or mobile application targeting a platform supported by the OpenIddict client (including Android, iOS, Linux, macOS and Windows).
Supported services
Differences with the aspnet-contrib social providers
While the OpenIddict Web providers share some similarities with the existing aspnet-contrib OAuth 2.0 providers, there are actually important technical differences:
OpenIddict fully supports OpenID Connect, which allows enforcing additional security checks for providers that implement it.
The OpenIddict client is stateful and provides built-in countermeasures against nonce/token replay attacks.
While the aspnet-contrib providers only support the OAuth 2.0 code flow, the OpenIddict providers support additional flows, including the OpenID Connect hybrid flow, the OAuth 2.0 client credentials grant, the resource owner password credentials grant or the refresh token grant.
The OpenIddict client supports OAuth 2.0 token introspection and OAuth 2.0 token revocation.
OpenIddict uses OAuth 2.0 and OpenID Connect server configuration discovery to avoid hardcoding the endpoint URIs of a provider when possible, making the OpenIddict Web providers more robust and more future-proof.
While the aspnet-contrib providers require targeting the latest ASP.NET Core version, the OpenIddict Web providers can be used in any supported version. They can also be used in ASP.NET 4.6.1+ websites and mobile/desktop applications.
OpenIddict uses
Microsoft.Extensions.Http.Polly
(orMicrosoft.Extensions.Http.Resilience
on .NET 8+) to make backchannel HTTP communications less prone to transient network errors.
As such, while the aspnet-contrib providers are still fully supported, developers are encouraged to use the OpenIddict client for new applications.
Basic configuration
IMPORTANT
Being an extension to the OpenIddict client, the OpenIddict Web integration requires a properly configured client.
For more information on how to get started with the OpenIddict client, read Integrating with a remote server instance.
To configure the System.Net.Http
integration, you'll need to:
- Reference the
OpenIddict.Client.WebIntegration
package:
<PackageReference Include="OpenIddict.Client.WebIntegration" Version="5.8.0" />
- Call
UseWebProviders()
in the client options:
services.AddOpenIddict()
.AddClient(options =>
{
// ...
// Register the Web providers integrations.
options.UseWebProviders();
});
- To add a provider instance, call the corresponding
Add[Provider name]()
method and configure the required settings:
services.AddOpenIddict()
.AddClient(options =>
{
// Note: to mitigate mix-up attacks, it's recommended to use a unique redirection endpoint
// URI per provider, unless all the registered providers support returning a special "iss"
// parameter containing their URL as part of authorization responses. For more information,
// see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.4.
options.UseWebProviders()
.AddGitHub(options =>
{
options.SetClientId("[client identifier]")
.SetClientSecret("[client secret]")
.SetRedirectUri("callback/login/github");
})
.AddTwitter(options =>
{
options.SetClientId("[client identifier]")
.SetClientSecret("[client secret]")
.SetRedirectUri("callback/login/twitter");
});
});
TIP
Once enabled, authentication operations (e.g challenges) can be triggered using the default provider name assigned by OpenIddict:
- In an ASP.NET Core application, using the authentication APIs provided by ASP.NET Core:
[HttpPost("~/login"), ValidateAntiForgeryToken]
public async Task<ActionResult> LogInWithGitHub(string returnUrl)
{
var properties = new AuthenticationProperties
{
// Only allow local return URLs to prevent open redirect attacks.
RedirectUri = Url.IsLocalUrl(returnUrl) ? returnUrl : "/"
};
// Ask the OpenIddict client middleware to redirect the user agent to GitHub.
return Challenge(properties, OpenIddictClientWebIntegrationConstants.Providers.GitHub);
}
- In a desktop or mobile application (e.g WPF), using the APIs exposed by
OpenIddictClientService
:
public partial class MainWindow : Window, IWpfShell
{
private readonly OpenIddictClientService _service;
public MainWindow(OpenIddictClientService service)
{
_service = service ?? throw new ArgumentNullException(nameof(service));
InitializeComponent();
}
private async void LoginButton_Click(object sender, RoutedEventArgs e)
{
// Disable the login button to prevent concurrent authentication operations.
LoginButton.IsEnabled = false;
try
{
using var source = new CancellationTokenSource(delay: TimeSpan.FromSeconds(90));
try
{
// Ask OpenIddict to initiate the authentication flow (typically, by starting the system browser).
var result = await _service.ChallengeInteractivelyAsync(new()
{
CancellationToken = source.Token,
ProviderName = OpenIddictClientWebIntegrationConstants.Providers.GitHub
});
// Wait for the user to complete the authorization process.
var principal = (await _service.AuthenticateInteractivelyAsync(new()
{
CancellationToken = source.Token,
Nonce = result.Nonce
})).Principal;
MessageBox.Show($"Welcome, {principal.FindFirst(ClaimTypes.Name)!.Value}.",
"Authentication successful", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (OperationCanceledException)
{
MessageBox.Show("The authentication process was aborted.",
"Authentication timed out", MessageBoxButton.OK, MessageBoxImage.Warning);
}
catch (ProtocolException exception) when (exception.Error is Errors.AccessDenied)
{
MessageBox.Show("The authorization was denied by the end user.",
"Authorization denied", MessageBoxButton.OK, MessageBoxImage.Warning);
}
catch
{
MessageBox.Show("An error occurred while trying to authenticate the user.",
"Authentication failed", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
finally
{
// Re-enable the login button to allow starting a new authentication operation.
LoginButton.IsEnabled = true;
}
}
}
Advanced configuration
Register multiple instances of the same provider
Registering multiple instances of the same provider is fully supported but requires specifying a different provider name for each provider registration if you use the ProviderName
property to trigger authentication operations.
services.AddOpenIddict()
.AddClient(options =>
{
options.UseWebProviders()
.AddGitHub(options =>
{
options.SetClientId("[client identifier A]")
.SetClientSecret("[client secret A]")
.SetRedirectUri("callback/login/github/a")
.SetProviderName("GitHub-Instance-A");
})
.AddGitHub(options =>
{
options.SetClientId("[client identifier B]")
.SetClientSecret("[client secret B]")
.SetRedirectUri("callback/login/github/b")
.SetProviderName("GitHub-Instance-B");
});
});
[HttpPost("~/login"), ValidateAntiForgeryToken]
public async Task<ActionResult> LogInWithGitHubInstanceA(string returnUrl)
{
var properties = new AuthenticationProperties
{
// Only allow local return URLs to prevent open redirect attacks.
RedirectUri = Url.IsLocalUrl(returnUrl) ? returnUrl : "/"
};
// Ask the OpenIddict client middleware to redirect the
// user agent to GitHub using the "Instance A" settings.
return Challenge(properties, "GitHub-Instance-A");
}
WARNING
While not strictly required, using a different redirect_uri
per provider instance is strongly recommended to help mitigate mix-up attacks.
Configure a different display name that will be visible by the users
When using ASP.NET Core Identity and its default UI, the login page automatically lists the external providers configured in the application, including the OpenIddict Web providers.
While OpenIddict automatically assigns a default display name, that value can be overridden using the SetProviderDisplayName()
API:
services.AddOpenIddict()
.AddClient(options =>
{
options.UseWebProviders()
.AddGitHub(options =>
{
options.SetClientId("[client identifier]")
.SetClientSecret("[client secret]")
.SetRedirectUri("callback/login/github")
.SetProviderDisplayName("Log in with GitHub™️");
});
});