English | 繁體中文
Lightweight sign-in for .NET with OAuth2 and OpenID Connect (OIDC). Desktop and console applications sign in through the system
browser with a loopback redirect and PKCE, directly or through their own back end, on Windows, macOS and Linux. .NET MAUI applications on Android, iOS and Mac
Catalyst sign in through WebAuthenticator, directly or through their own back end. ASP.NET Core and ASP.NET (System.Web)
applications use the authorization code flow with PKCE, and keep each sign-in in a protected cookie.
Every account signs in with the OAuth2 authorization code flow. "OAuth2 + OIDC" means the account also returns an OIDC ID token, which the library checks or reads the user from; "OAuth2" means the user comes from the provider's own API.
| Account | Protocol | Desktop and console | .NET MAUI | ASP.NET Core and System.Web |
|---|---|---|---|---|
| OAuth2 + OIDC | Directly or through the back end | Directly on iOS and Mac Catalyst; through the back end on Android | Yes | |
| OAuth2 | Directly or through the back end | Directly or through the back end | Yes | |
| LINE | OAuth2, with the email address from the OIDC ID token | Directly or through the back end | Directly on iOS and Mac Catalyst; through the back end on Android | Yes |
| Microsoft Entra ID | OAuth2 + OIDC | Directly or through the back end | Directly or through the back end | Yes |
| Auth0 | OAuth2 + OIDC | Directly or through the back end | Directly or through the back end | Yes |
| Okta | OAuth2 + OIDC | Directly or through the back end | Directly or through the back end | Yes |
| GitHub | OAuth2 | Directly or through the back end | Through the back end only | Yes |
| Apple | OAuth2 + OIDC | Through the back end only | Through the back end only | Yes |
| Any other OIDC provider, such as Keycloak or GitLab | OAuth2 + OIDC | Directly when the provider accepts a public client, or through the back end | Directly or through the back end | Yes |
"Through the back end" means that the application signs in through its own ASP.NET Core back end, which an application with a back end always does: see Applications with a back end. Each account's document says what to register with the provider and what it was tested with.
| Package | Target frameworks | Use it for |
|---|---|---|
| Polhem.OAuth2 | netstandard2.0, net8.0, net10.0 | The providers, sign-in from desktop, console and .NET MAUI applications, and other server frameworks |
| Polhem.OAuth2.AspNetCore | net10.0 | ASP.NET Core applications |
| Polhem.OAuth2.AspNet | net472 | ASP.NET Web Forms and MVC applications on System.Web |
dotnet add package Polhem.OAuth2The web packages depend on Polhem.OAuth2, so a web application adds only its own package, such as
dotnet add package Polhem.OAuth2.AspNetCore.
1.x minor versions may contain breaking changes, which the changelog
marks. Reference the packages with a range that stays within one minor version, for example [1.4,1.5), rather than 1.*
(ADR-010).
LoopbackOAuth2Client listens on the redirect URI, opens the sign-in in the default browser, and exchanges the code
when Google redirects back. Create an OAuth client of the Desktop app type in the Google Cloud console.
using Polhem.OAuth2;
var options = new GoogleOAuth2Options
{
ClientId = "your-client-id",
ClientSecret = "your-client-secret",
RedirectUri = "http://127.0.0.1:0/callback"
};
var client = new LoopbackOAuth2Client(options);
AuthorizationResult result = await client.SignInAsync();
if (result.IsSuccess)
Console.WriteLine($"{result.UserInfo.UserId} {result.UserInfo.UserName} {result.UserInfo.Email}");
else
Console.WriteLine($"The sign-in failed: {result.Exception.Message}");Create an OAuth client of the Web application type, and register the callback URL as its redirect URI.
using Polhem.OAuth2;
builder.Services.AddControllers();
builder.Services.AddOAuth2Client("Google", new GoogleOAuth2Options
{
ClientId = "your-client-id",
ClientSecret = "your-client-secret",
RedirectUri = "https://localhost:7032/auth/callback"
});
var app = builder.Build();
app.MapControllers();using Microsoft.AspNetCore.Mvc;
using Polhem.OAuth2;
using Polhem.OAuth2.AspNetCore;
public class AuthController(OAuth2Manager oauth2Manager) : ControllerBase
{
[HttpGet("/auth/login")]
public IActionResult Login()
{
return Redirect(oauth2Manager.CreateAuthorizationUrl(HttpContext, "Google"));
}
[HttpGet("/auth/callback")]
public async Task<IActionResult> Callback()
{
AuthorizationResult result = await oauth2Manager.CompleteAuthorizationAsync(HttpContext, HttpContext.RequestAborted);
return result.IsSuccess
? Content($"{result.UserInfo.UserId} {result.UserInfo.UserName} {result.UserInfo.Email}")
: Content($"The sign-in failed: {result.Exception.Message}");
}
}OidcOAuth2Options.FromDiscoveryAsync reads the endpoints from the provider's discovery document. Call it once, when the
application starts:
var keycloak = await OidcOAuth2Options.FromDiscoveryAsync("https://sso.example.com/realms/example");
keycloak.ProviderName = "Keycloak";
keycloak.ClientId = "your-client-id";
keycloak.ClientSecret = "your-client-secret";
keycloak.RedirectUri = "https://localhost:7032/auth/callback";
builder.Services.AddOAuth2Client("Keycloak", keycloak);The controller above works unchanged. For another OpenID Connect provider, such as GitLab or AWS Cognito, pass that
provider's address instead, and give it a ProviderName of its own. A provider that has options of its own, such as
Google, signs in with those options instead.
Each account's document is linked from the table in "Supported accounts". The guides cover each kind of application and the topics they share:
- Options shared by every provider
- Desktop and console applications
- .NET MAUI applications
- ASP.NET Core
- ASP.NET (System.Web)
- Web applications: how a sign-in is kept
- Other server frameworks
- Applications with a back end
- Results, tokens and errors
- Identifying users
- Migrating from Bee.OAuth2
- Samples
The reasons behind the design are recorded in the architecture decision records.
MIT. Copyright (c) Polhem contributors.
Polhem.OAuth2 continues Bee.OAuth2.