OpenID Connect
Lagoon exposes an AddOidc extension method to register an OpenID Connect provider on the server side.
NuGet reference
It is no longer necessary to explicitly add the Microsoft.AspNetCore.Authentication.OpenIdConnect package when you use the AddOidc method.
Register the service
Add the required namespaces in the Main.cs file of the server project.
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using System.Security.Claims;
In OnConfigureServices, register the OIDC provider.
protected override void OnConfigureServices(IServiceCollection services)
{
Services.Registry.RegisterServices(services);
IConfiguration config = Configuration;
services.AddAuthentication().AddOidc("SSO", "Explicit", options =>
{
options.Authority = config["Oidc:Authority"];
options.ClientId = config["Oidc:ClientId"];
options.ClientSecret = config["Oidc:ClientSecret"];
options.CallbackPath = "/sso-callback";
options.ResponseType = OpenIdConnectResponseType.Code;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.TokenValidationParameters = new TokenValidationParameters
{
// Utilise l'adresse e-mail comme nom de l'identité ASP.NET Core.
NameClaimType = ClaimTypes.Email
};
});
}
{
"Oidc": {
"Authority": "https://identity-provider.example",
"ClientId": "client-id",
"ClientSecret": "client-secret"
}
}
Okta and group management
With Okta, add the groups scope to receive the user's groups in the returned claims.
services.AddAuthentication().AddOidc("SSO", "Explicit", options =>
{
options.Authority = config["Oidc:Authority"];
options.ClientId = config["Oidc:ClientId"];
options.ClientSecret = config["Oidc:ClientSecret"];
options.CallbackPath = "/sso-callback";
options.ResponseType = OpenIdConnectResponseType.Code;
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Scope.Add("groups");
options.TokenValidationParameters = new TokenValidationParameters
{
// Utilise l'adresse e-mail comme nom de l'identité ASP.NET Core.
NameClaimType = ClaimTypes.Email
};
});
The groups can then be read from the authentication context.
protected override Task OnSignInAsync(AuthenticationContext context, ApplicationUser user)
{
string groups = context.IdentitySource.Claims?
.Where(claim => claim.Type == "groups")
.FirstOrDefault()?.Value;
return Task.CompletedTask;
}
Forced reconnection
With OIDC, you can ask an already authenticated user to reconnect before performing a critical action. There is nothing to do on the OIDC configuration side: support is built into AddOidc.
Client side
Call ReconnectAsync. The method opens a popup to the configured OIDC SSO. Once the process is complete, you get a Guid to pass to the backend on the endpoint that requires reconnection.
private async Task DoSomethingAsync()
{
Guid? id = await App.ReconnectAsync();
if (id.HasValue)
{
List<string> data = await Http.TryGetAsync<List<string>>($"api/monController/monAction?reconnectId={id}");
}
else
{
// L'utilisateur a fermé la popup ou la reconnexion a échoué.
ShowWarning("#reconnectionFailed");
}
}
Server side
Call ValidateReconnectionAsync with the identifier obtained from ReconnectAsync. The method throws an exception if reconnectId is not valid or does not match the identity of the connected user.
[Authorize(Policy = Policies.AuthenticatedUser)]
[HttpGet]
public async Task<IEnumerable<string>> Get(string reconnectId)
{
// Vérifie que l'utilisateur s'est bien reconnecté pour cette demande.
await _app.ValidateReconnectionAsync(reconnectId);
return Array.Empty<string>();
}
Notes
- Forced reconnection is only supported if the configured SSO uses the
OIDCprotocol. - In development, if you use form-based authentication, you can set
App:ReconnectionDisabledtotrue. In that case,ReconnectAsyncreturns an identifier andValidateReconnectionAsyncconsiders it valid. - Special case with Cognito configured to relay authentication to another OIDC IDP: specify the provider to use with
Lagoon:SSOReconnectProviderName.
{
"App": {
"ReconnectionDisabled": true
},
"Lagoon": {
"SSOReconnectProviderName": "LeNomDuProviderConfigureDansCognito"
}
}