Search code examples
.net-coreidentityserver4

Is there any possibility return the access_token with only user object?


I am implementing a functionality, where access_token will be sent via email, in this case I need to generate this token with a logic to authenticate the user when accessing the link passed via email.

public async Task<IActionResult> GetLink () 
{
    var user = await userManager.FindByEmailAsync("[email protected]"); // is active user created
    if (user != null)
    {
        var ident = await userManager.GetAuthenticationTokenAsync(user, "Test", "access_token");
        return Ok(ident);
    }
    return NoContent();
}

Based on the research expected would be something like this, but this is not done with persisted data and my model is not allowing this, anyone have any idea how to persist? Or even just return the token?

I think it is a bad behavior not is not acceptable, but, my user dont have a password for access in this case, maybe is necessary using the token or another mode to login. It is a very simple flow, this link would be one for a granted action (it will only have read access, basically), and this link will be sent only to a user via email.


Solution

  • The above problem can be solved as follows:

    [HttpGet("get_token")]
    [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(string))]
    [ProducesResponseType(StatusCodes.Status404NotFound)]
    public async Task<IActionResult> GetUserToken([FromServices] ITokenService TS, [FromServices] IUserClaimsPrincipalFactory<EkyteUser> principalFactory,
    [FromServices] IdentityServerOptions options)
    {           
        var Request = new TokenCreationRequest();                        
        var user = await userManager.FindByIdAsync(User.GetSubjectId());
        var IdentityPricipal = await principalFactory.CreateAsync(user);
        var IdServerPrincipal = IdentityServerPrincipal.Create(user.Id.ToString(), user.UserName);
    
        Request.Subject = IdServerPrincipal;
        Request.IncludeAllIdentityClaims = true;
        Request.ValidatedRequest = new ValidatedRequest();
        Request.ValidatedRequest.Subject = Request.Subject;
        Request.ValidatedRequest.SetClient(Config.GetClient());
        Request.Resources = new Resources(Config.GetResources(), Config.GetApiResources());
        Request.ValidatedRequest.Options = options;            
        var Token = await TS.CreateAccessTokenAsync(Request);
        Token.Issuer = "http://" + HttpContext.Request.Host.Value;
    
        var TokenValue = await TS.CreateSecurityTokenAsync(Token);
        return Ok(TokenValue);
    }
    

    It is necessary to identify the user, set the necessary resources and consequently the client that is accessing. After that, just include the access host to generate the token.