Openiddict-core: Client Credentials flow with openiddict 3.x

Created on 27 Feb 2020  路  2Comments  路  Source: openiddict/openiddict-core

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?

question

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:

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);
    }
}

All 2 comments

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);
    }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

biapar picture biapar  路  5Comments

levitatejay picture levitatejay  路  3Comments

ksmuthuus picture ksmuthuus  路  3Comments

xperiandri picture xperiandri  路  4Comments

ivanmariychuk picture ivanmariychuk  路  6Comments