1 using Microsoft.IdentityModel.Tokens;
4 using System.IdentityModel.Tokens.Jwt;
6 using System.Security.Claims;
8 using System.Threading.Tasks;
20 const uint TokenExpiryMinutes = 15;
25 const uint TokenClockSkewMinutes = 1;
30 const uint TokenSigningKeyByteAmount = 256;
33 public TokenValidationParameters ValidationParameters {
get; }
47 ValidationParameters =
new TokenValidationParameters
49 ValidateIssuerSigningKey =
true,
50 IssuerSigningKey =
new SymmetricSecurityKey(cryptographySuite.
GetSecureBytes(TokenSigningKeyByteAmount)),
52 ValidateIssuer =
true,
53 ValidIssuer = Assembly.GetExecutingAssembly().GetName().Name,
55 ValidateLifetime =
true,
56 ValidateAudience =
true,
57 ValidAudience = typeof(
Token).Assembly.GetName().Name,
59 ClockSkew = TimeSpan.FromMinutes(TokenClockSkewMinutes),
61 RequireSignedTokens =
true,
63 RequireExpirationTime =
true 66 this.asyncDelayer = asyncDelayer ??
throw new ArgumentNullException(nameof(asyncDelayer));
70 public async Task<Token>
CreateToken(Models.User user, CancellationToken cancellationToken)
73 throw new ArgumentNullException(nameof(user));
75 var now = DateTimeOffset.Now;
77 var nowUnix = now.ToUnixTimeSeconds();
83 var lpuUnix = user.LastPasswordUpdate?.ToUnixTimeSeconds();
84 if (nowUnix == lpuUnix)
85 await asyncDelayer.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(
false);
87 var expiry = now.AddMinutes(TokenExpiryMinutes);
88 var claims =
new Claim[]
90 new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString(CultureInfo.InvariantCulture)),
91 new Claim(JwtRegisteredClaimNames.Exp, expiry.ToUnixTimeSeconds().ToString(CultureInfo.InvariantCulture)),
92 new Claim(JwtRegisteredClaimNames.Nbf, nowUnix.ToString(CultureInfo.InvariantCulture)),
93 new Claim(JwtRegisteredClaimNames.Iss, ValidationParameters.ValidIssuer),
94 new Claim(JwtRegisteredClaimNames.Aud, ValidationParameters.ValidAudience)
97 var token =
new JwtSecurityToken(
new JwtHeader(
new SigningCredentials(ValidationParameters.IssuerSigningKey, SecurityAlgorithms.HmacSha256)),
new JwtPayload(claims));
98 return new Token { Bearer =
new JwtSecurityTokenHandler().WriteToken(token), ExpiresAt = expiry };
Use server authentication
byte[] GetSecureBytes(uint amount)
Generates a secure set of bytes
For waiting asynchronously
Contains various cryptographic functions
readonly IAsyncDelayer asyncDelayer
The IAsyncDelayer for the TokenFactory
Represents a JWT returned by the API
TokenFactory(IAsyncDelayer asyncDelayer, ICryptographySuite cryptographySuite)
Construct a TokenFactory
async Task< Token > CreateToken(Models.User user, CancellationToken cancellationToken)
Create a Token for a given user