Skip to content

Instantly share code, notes, and snippets.

@tnishimura
Last active September 5, 2023 10:00
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tnishimura/370892e5816b2c36818ecaa277b8d22d to your computer and use it in GitHub Desktop.
Save tnishimura/370892e5816b2c36818ecaa277b8d22d to your computer and use it in GitHub Desktop.
This is an F# interactive script to generate a JWT. You can use it as a reference for when you are generating JWT on your server for a client, for example. It is hard coded for symmetric signing (HS256), but can be modified for asymmetric signing RS256, see notes in code.
(*
This is an F# interactive script to generate a JWT. You can use it as a reference for when you are generating JWT on
your server for a client, for example. It is hard coded for symmetric signing (HS256), but can be modified for
asymmetric signing RS256, see notes.
*)
#r "nuget: System.IdentityModel.Tokens.Jwt"
open System
open System.Text // for Encoding
open System.IdentityModel.Tokens.Jwt // For JwtSecurityToken (Install it from Nuget)
open System.Security.Claims // For Claim, ClaimTypes
open Microsoft.IdentityModel.Tokens // For SymmetricSecurityKey, SigningCredentials, SecurityAlgorithms (Install it from Nuget)
// Adjust these parameters to suit your needs
let expiration = 2.0 * 365.0 * 24.0 * 60.0 // in minutes. in reality it would be much, much lower
// (~1 hour. use refresh tokens instead for long lived tokens)
let key = "pleaseReplaceWithYourSecretKeyRetrievedFromSomeSecureLocation"
let issuer = "https://certificateissuer.example.com/"
let audience = "https://backendserver.example.com"
let name = "Some User"
let role = "User"
let dob = "1995/02/23"
// These claims get added to the payload part of the jwt. Add anything you like from the ClaimTypes namespace!
let claims = [|
new Claim("CustomClaim", "value")
// http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
new Claim(ClaimTypes.Name, name)
// http://schemas.microsoft.com/ws/2008/06/identity/claims/role
new Claim(ClaimTypes.Role, role)
// http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth
new Claim(ClaimTypes.DateOfBirth, dob)
|]
// Set up symmetric key
let securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
let credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); // HS256
// SecurityAlgorithms.HmacSha256Signature
// IF YOU WANT TO DO PUBLIC KEY SIGNING (RS256) INSTEAD (see below for generation tips):
// open System.Security.Cryptography // For RSA
// let rsa = RSA.Create()
// rsa.ImportFromPem(pemKeyAsString.AsSpan())
// let securityKey = new RsaSecurityKey(rsa)
// let credentials = new SigningCredentials( securityKey, SecurityAlgorithms.RsaSha256);
let tokenDescriptor : JwtSecurityToken =
new JwtSecurityToken(
// iss
issuer,
// aud
audience,
claims,
// nbf - "not before". I've rarely seen this one used.
System.Nullable(),
// expiration (seconds since epoch)
DateTime.Now.AddMinutes(expiration),
credentials)
let token = (new JwtSecurityTokenHandler()).WriteToken(tokenDescriptor);
// Prints three lines: the header of the JWT in json format, the payload in json format, and the token
printfn "%s" (tokenDescriptor.Header.SerializeToJson())
printfn "%s" (tokenDescriptor.Payload.SerializeToJson())
printfn "%s" (string token)
(*
If you are merely playing around, an easy way to generate an RSA keypair in F# is:
open System
open System.Security.Cryptography
let rsa = RSA.Create()
printfn "-----BEGIN RSA PUBLIC KEY-----\n%s\n-----END RSA PUBLIC KEY-----\n" (Convert.ToBase64String(rsa.ExportRSAPublicKey()))
printfn "-----BEGIN RSA PRIVATE KEY-----\n%s\n-----END RSA PRIVATE KEY-----\n" (Convert.ToBase64String(rsa.ExportRSAPrivateKey()))
Of course, in production you'd want to generate it with openssl or some other tool
*)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment