I have a website where users log in on an external website and are redirected back with a token in the querystring. I then validate the token and create the authentication ticket. How would I check on subsequent requests that the user is now logged in? And how would I log a user out?
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var token = Request.Query["token"].FirstOrDefault();
if (token != null)
{
var validator = new JwtSecurityTokenHandler();
var region = "us-xxx-x";
var userPoolId = "us-xxx-xxxxxxx";
var appClientId = "xxxxxxxxxxxxxxxxxxxx";
var cognitoIssuer = $"https://cognito-idp.{region}.amazonaws.com/{userPoolId}";
var jwtKeySetUrl = $"{cognitoIssuer}/.well-known/jwks.json";
var validationParameters = new TokenValidationParameters
{
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
var json = new WebClient().DownloadString(jwtKeySetUrl);
var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
return (IEnumerable<SecurityKey>)keys;
},
ValidIssuer = cognitoIssuer,
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidAudience = appClientId
};
// validate the token
var principal = validator.ValidateToken(token, validationParameters, out var validatedToken);
if (principal.HasClaim(c => c.Type == ClaimTypes.NameIdentifier))
{
var claims = new[] { new Claim("token", token) };
var identity = new ClaimsIdentity(claims, nameof(TokenAuthenticationHandler));
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), this.Scheme.Name);
return Task.FromResult(AuthenticateResult.Success(ticket));
}
else
return Task.FromResult(AuthenticateResult.Fail("Token validation failed"));
}
else
return Task.FromResult(AuthenticateResult.Fail("No token"));
}
2
Answers
Full disclosure, I’m not very knowledgeable on the library you are using or on what exactly you are trying to do here, but I can tell you how these things work, generally speaking. Conceptually logging in and out on a web service works as follows:
Client sends authentication information to the server (Username, password hash, 2FA info, etc.)
The server checks the authentication information against the stored information about the user (e.g. compare password hash to the stored password hash)
If authentication is sucessful, the server creates and stores a cookie (a long randomly generated string). The server stores the cookie along with information such as the user who the cookie belongs to, and when the cookie was created.
The server sends the cookie to the client. The client is now "logged in".
Now when the client wants to send some http request to the web service, they send the cookie along with the request. The server then looks up who the cookie belongs to and handles the http request appropriately.
When the user wants to log out they send an http request to the server asking to log out, and pass the cookie along with the message. The server then invalidates the cookie, and further http requests are handled as if the user is logged out.
I tried with the code:
In controller:
In startup:
The Result:
you could modify the codes in login controller to pool data from database and varify the userinformation to meet your requirement.
And the Attribute[Authorize(AuthenticationSchemes = "Cookies,Bearer")] allows you Authentication with cookie or jwt,it may help in some situation
and if you want to logout,you could delete the cookie which strores the token or ticket
UpDate:
Accroding to your description,I think you could use jwt Authentication and set in your startup as follow:
Is it the result you excepted?