Skip to content

Instantly share code, notes, and snippets.

@szilardd
Created January 12, 2023 12:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save szilardd/3ba1169d11d99b0ec5181253763775d0 to your computer and use it in GitHub Desktop.
Save szilardd/3ba1169d11d99b0ec5181253763775d0 to your computer and use it in GitHub Desktop.
How to add a custom grant type in OpenIddict for existing user
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Abstractions;
using OpenIddict.Server;
using OpenIddict.Server.AspNetCore;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Identity;
using Volo.Abp.OpenIddict;
using Volo.Abp.OpenIddict.ExtensionGrantTypes;
using Volo.Abp.Security.Claims;
namespace MyProject
{
public class MyTokenExtensionGrant : IExtensionGrant
{
public string Name => "MyTokenExtensionGrant";
public async Task<IActionResult> HandleAsync(ExtensionGrantContext context)
{
// get user id from request
var userId = context.Request.GetParameter("uid")?.Value?.ToString();
if (string.IsNullOrEmpty(userId))
{
return new ForbidResult
(
new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant
}
));
}
// retrieve user
var userManager = context.HttpContext.RequestServices.GetRequiredService<IdentityUserManager>();
var user = await userManager.FindByIdAsync(userId);
if (user == null)
{
return new ForbidResult
(
new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant
}
));
}
// generate temporary user token
var oidcOptions = context.HttpContext.RequestServices.GetRequiredService<IOptionsMonitor<OpenIddictServerOptions>>();
var options = oidcOptions.CurrentValue;
var descriptor = new SecurityTokenDescriptor
{
Claims = new Dictionary<string, object>
{
{ "sub", user.Id },
{ "scope", context.Request.GetParameter("scope")?.Value?.ToString() },
},
EncryptingCredentials = options.DisableAccessTokenEncryption
? null
: options.EncryptionCredentials.First(),
Expires = null, // recommended to set this
IssuedAt = DateTime.UtcNow,
SigningCredentials = options.SigningCredentials.First(),
TokenType = OpenIddictConstants.JsonWebTokenTypes.AccessToken
};
var userToken = options.JsonWebTokenHandler.CreateToken(descriptor);
// authenticate with temporary token
var transaction = await context.HttpContext.RequestServices.GetRequiredService<IOpenIddictServerFactory>().CreateTransactionAsync();
transaction.EndpointType = OpenIddictServerEndpointType.Introspection;
transaction.Request = new OpenIddictRequest
{
ClientId = context.Request.ClientId,
ClientSecret = context.Request.ClientSecret,
Token = userToken
};
var notification = new OpenIddictServerEvents.ProcessAuthenticationContext(transaction);
var dispatcher = context.HttpContext.RequestServices.GetRequiredService<IOpenIddictServerDispatcher>();
await dispatcher.DispatchAsync(notification);
var principal = notification.GenericTokenPrincipal;
if (principal == null)
{
return new ForbidResult(
new[] { OpenIddictServerAspNetCoreDefaults.AuthenticationScheme },
properties: new AuthenticationProperties(new Dictionary<string, string>
{
[OpenIddictServerAspNetCoreConstants.Properties.Error] = notification.Error ?? OpenIddictConstants.Errors.InvalidRequest,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = notification.ErrorDescription,
[OpenIddictServerAspNetCoreConstants.Properties.ErrorUri] = notification.ErrorUri
}));
}
// retrieve generic user claims
var userClaimsPrincipalFactory = context.HttpContext.RequestServices.GetRequiredService<IUserClaimsPrincipalFactory<Volo.Abp.Identity.IdentityUser>>();
var claimsPrincipal = await userClaimsPrincipalFactory.CreateAsync(user);
claimsPrincipal.SetScopes(principal.GetScopes());
claimsPrincipal.SetResources(await GetResourcesAsync(context, principal.GetScopes()));
// retrieve abp user claims
var abpClaimsPrincipalFactory = context.HttpContext.RequestServices.GetRequiredService<IAbpClaimsPrincipalFactory>();
var abpClaimsPrincipal = await abpClaimsPrincipalFactory.CreateAsync(claimsPrincipal);
await context.HttpContext.RequestServices.GetRequiredService<AbpOpenIddictClaimDestinationsManager>().SetAsync(abpClaimsPrincipal);
return new Microsoft.AspNetCore.Mvc.SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, abpClaimsPrincipal);
}
private async Task<IEnumerable<string>> GetResourcesAsync(ExtensionGrantContext context, ImmutableArray<string> scopes)
{
var resources = new List<string>();
if (!scopes.Any())
{
return resources;
}
await foreach (var resource in context.HttpContext.RequestServices.GetRequiredService<IOpenIddictScopeManager>().ListResourcesAsync(scopes))
{
resources.Add(resource);
}
return resources;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment