Search code examples
c#asp.net-coreopeniddict

OpenIddict get token_id before response


[AllowAnonymous]
[HttpPost("~/api/auth/login")]
[Produces("application/json")]
public async Task<IActionResult> Login(OpenIdConnectRequest request)
{
  ...
      var ticket = await CreateTicketAsync(request, user);
      _logger.LogInformation($"User logged in (id: {user.Id})");

      // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.

      return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
}

OpenIddict creates token after SignIn method is called right? How can i access created refresh_token token_id before response is sent?

I want to associate token_id with custom device_id and save to database. Then i will allow user to revoke refresh_token with specified device.


Solution

  • Here's how you can do with the latest RC2 packages (that you can find on the MyGet feed).

    1) Create custom entities derived from the built-in ones:

    public class MyApplication : OpenIddictApplication<string, MyAuthorization, MyToken>
    {
        public MyApplication() => Id = Guid.NewGuid().ToString();
    }
    
    public class MyAuthorization : OpenIddictAuthorization<string, MyApplication, MyToken>
    {
        public MyAuthorization() => Id = Guid.NewGuid().ToString();
    }
    
    public class MyScope : OpenIddictScope<string>
    {
        public MyScope() => Id = Guid.NewGuid().ToString();
    }
    
    public class MyToken : OpenIddictToken<string, MyApplication, MyAuthorization>
    {
        public MyToken() => Id = Guid.NewGuid().ToString();
    
        public string DeviceId { get; set; }
    }
    

    2) Update your authorization controller to store the device identifier as an authentication property:

    // ...
    var ticket = new AuthenticationTicket(principal, properties,
        OpenIdConnectServerDefaults.AuthenticationScheme);
    
    ticket.SetProperty("device_id", "[the device identifier]");
    // ...
    

    3) Create a custom token manager and override the PopulateAsync method to attach the device identifier to the token entry stored in the database:

    public class MyManager : OpenIddictTokenManager<MyToken>
    {
        public MyManager(
            IOpenIddictTokenStore<MyToken> store,
            ILogger<OpenIddictTokenManager<MyToken>> logger)
            : base(store, logger)
        {
        }
    
        protected override Task PopulateAsync(MyToken token, OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
        {
            if (descriptor.Properties.TryGetValue("device_id", out var identifier))
            {
                token.DeviceId = identifier;
            }
    
            return base.PopulateAsync(token, descriptor, cancellationToken);
        }
    }
    

    4) Update your Startup class to use the new entities and the custom manager:

    services.AddDbContext<ApplicationDbContext>(options =>
    {
        // ...
        options.UseOpenIddict<MyApplication, MyAuthorization, MyScope, MyToken, string>();
    });
    
    services.AddOpenIddict<MyApplication, MyAuthorization, MyScope, MyToken>(options =>
    {
        // ...
        options.AddTokenManager<MyManager>();
    });