With openiddict 2.x, we can use the following codes to issue a token.
var ticket = new AuthenticationTicket(
new ClaimsPrincipal(identity),
new AuthenticationProperties(),
OpenIddictServerDefaults.AuthenticationScheme);
return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
What's the best practice to do so with openiddict 3.x?
The concept is very similar, but we no longer use AuthenticationTicket (which an ASP.NET Core type). Instead, use ClaimsPrincipal as the source of truth:
var principal = new ClaimsPrincipal(identity);
principal.SetResources("resource_server");
return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
For those using OpenIddict 3.0's server feature in "legacy" ASP.NET/OWIN apps, the approach will be very similar. Here's an example with MVC 5:
public class ConnectController : Controller
{
[HttpPost]
public ActionResult Token()
{
var request = HttpContext.GetOwinContext()?.GetOpenIddictServerRequest() ??
throw new InvalidOperationException("The OpenID Connect request cannot be retrieved.");
if (request.IsPasswordGrantType())
{
// Validate the username/password parameters.
// In a real-world app, you'd of course use a time-constant comparer to avoid timing attacks.
if (!string.Equals(request.Username, "[email protected]", StringComparison.Ordinal) ||
!string.Equals(request.Password, "P@ssw0rd", StringComparison.Ordinal))
{
return new ChallengeResult(
authenticationType: OpenIddictServerOwinDefaults.AuthenticationType,
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerOwinConstants.Properties.Error] = Errors.InvalidGrant,
[OpenIddictServerOwinConstants.Properties.ErrorDescription] = "The username/password couple is invalid."
}));
}
var principal = new ClaimsPrincipal(new ClaimsIdentity(OpenIddictServerOwinDefaults.AuthenticationType));
principal.SetClaim(Claims.Subject, "Bob");
// Note: in this sample, the granted scopes match the requested scope
// but you may want to allow the user to uncheck specific scopes.
// For that, simply restrict the list of scopes before calling SetScopes.
principal.SetScopes(request.GetScopes());
principal.SetResources("resource_server");
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
return new SignInResult((ClaimsIdentity) principal.Identity);
}
throw new InvalidOperationException("The specified grant type is not supported.");
}
internal class SignInResult : ActionResult
{
public SignInResult(ClaimsIdentity identity)
=> Identity = identity ?? throw new ArgumentNullException(nameof(identity));
public ClaimsIdentity Identity { get; }
public override void ExecuteResult(ControllerContext context)
=> context.HttpContext.GetOwinContext().Authentication.SignIn(Identity);
}
internal class ChallengeResult : ActionResult
{
public ChallengeResult(AuthenticationProperties properties, string authenticationType)
{
Properties = properties;
AuthenticationType = authenticationType;
}
public AuthenticationProperties Properties { get; }
public string AuthenticationType { get; }
public override void ExecuteResult(ControllerContext context)
=> context.HttpContext.GetOwinContext().Authentication.Challenge(Properties, AuthenticationType);
}
}
Most helpful comment
For those using OpenIddict 3.0's server feature in "legacy" ASP.NET/OWIN apps, the approach will be very similar. Here's an example with MVC 5: