/// <summary> /// Validate tokens /// </summary> /// <param name="config">JwtConfig</param> /// <param name="token">Token value</param> public static Maybe <ClaimsPrincipal> ValidateToken(JwtConfig config, string token) { try { // Create validation parameters var parameters = new TokenValidationParameters { RequireExpirationTime = true, ValidIssuer = config.Issuer, ValidAudience = config.Audience ?? config.Issuer, IssuerSigningKey = config.GetSigningKey() }; _ = config.GetEncryptingKey().IfSome(encryptingKey => parameters.TokenDecryptionKey = encryptingKey); // Create handler to validate token var handler = new JwtSecurityTokenHandler(); // Validate token and return principal return(handler.ValidateToken(token, parameters, out var validatedToken)); } catch (SecurityTokenNotYetValidException) { return(F.None <ClaimsPrincipal, M.TokenIsNotValidYetMsg>()); } catch (Exception e) when(e.Message.Contains("IDX10223")) { return(F.None <ClaimsPrincipal, M.TokenHasExpiredMsg>()); } catch (Exception e) { return(F.None <ClaimsPrincipal, M.ValidatingTokenExceptionMsg>(e)); } }
/// <summary> /// <para>Generate a new JSON Web Token for the specified user</para> /// <para>See <see cref="JwtSecurity"/> for default signing and encrypting algorithms</para> /// </summary> /// <param name="config">JwtConfig</param> /// <param name="principal">ClaimsPrincipal</param> /// <param name="notBefore">The earliest date / time from which this token is valid</param> /// <param name="expires">The latest date / time before which this token is valid</param> internal static Maybe <string> CreateToken( JwtConfig config, ClaimsPrincipal principal, DateTime notBefore, DateTime expires ) { // Ensure there is a current user if (principal.Identity is null) { return(F.None <string, M.NullIdentityMsg>()); } // Ensure the current user is authenticated var identity = principal.Identity; if (!identity.IsAuthenticated) { return(F.None <string, M.IdentityNotAuthenticatedMsg>()); } // Ensure the JwtConfig is valid if (!config.IsValid) { return(F.None <string, M.ConfigInvalidMsg>()); } // Ensure the signing key is a valid length if (config.SigningKey.Length < JwtSecurity.SigningKeyBytes) { return(F.None <string, M.SigningKeyNotLongEnoughMsg>()); } // Ensure the encrypting key is a valid length if (config.EncryptingKey is string key && key.Length < JwtSecurity.EncryptingKeyBytes) { return(F.None <string, M.EncryptingKeyNotLongEnoughMsg>()); } try { // Create token values var descriptor = new SecurityTokenDescriptor { Issuer = config.Issuer, Audience = config.Audience ?? config.Issuer, Subject = new ClaimsIdentity(identity), NotBefore = notBefore, Expires = expires, IssuedAt = DateTime.UtcNow, SigningCredentials = new SigningCredentials(config.GetSigningKey(), JwtSecurity.SigningAlgorithm) }; _ = config.GetEncryptingKey().IfSome(encryptingKey2 => descriptor.EncryptingCredentials = new EncryptingCredentials( encryptingKey2, JwtSecurity.KeyWrapAlgorithm, JwtSecurity.EncryptingAlgorithm ) ); // Create handler to create and write token var handler = new JwtSecurityTokenHandler(); var token = handler.CreateJwtSecurityToken(descriptor); return(handler.WriteToken(token)); } catch (ArgumentOutOfRangeException e) when(e.Message.Contains("IDX10653")) { return(F.None <string, M.KeyNotLongEnoughMsg>()); } catch (Exception e) { return(F.None <string>(new M.CreatingJwtSecurityTokenExceptionMsg(e))); } }