https://github.com/deanpdx/jwt-secret
Quick and easy way to generate a cryptographically secure JWT signing secret
https://github.com/deanpdx/jwt-secret
Last synced: 7 months ago
JSON representation
Quick and easy way to generate a cryptographically secure JWT signing secret
- Host: GitHub
- URL: https://github.com/deanpdx/jwt-secret
- Owner: DeanPDX
- License: mit
- Created: 2024-09-06T16:10:47.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2024-09-21T17:12:19.000Z (over 1 year ago)
- Last Synced: 2025-01-01T12:46:03.529Z (over 1 year ago)
- Language: Go
- Size: 10.7 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# jwt-secret [](https://pkg.go.dev/github.com/DeanPDX/jwt-secret)
This is a utility for internal use to generate a base64-encoded cryptographically secure JWT signing secret using [crypto/rand](https://pkg.go.dev/crypto/rand).
## Usage
Run `go run github.com/DeanPDX/jwt-secret@latest` and you will see the following:
```bash
Which signing method are you using?
1. HS256
2. HS384
3. HS512
:
```
Enter a value based on which signing algorithm you're using and you will get an appropriate key.
## Why?
See [this issue](https://github.com/golang-jwt/jwt/issues/385) for the genesis of this utility. Specifically the quote from [RFC 7518](https://www.rfc-editor.org/rfc/rfc7518#section-3.2) about key size:
> Hash-based Message Authentication Codes (HMACs) enable one to use a
> secret plus a cryptographic hash function to generate a MAC. This
> can be used to demonstrate that whoever generated the MAC was in
> possession of the MAC key. The algorithm for implementing and
> validating HMACs is provided in [RFC 2104](https://www.rfc-editor.org/rfc/rfc2104) [[RFC2104](https://www.rfc-editor.org/rfc/rfc2104)].
>
> A key of the same size as the hash output (for instance, 256 bits for
> "HS256") or larger MUST be used with this algorithm. (This
> requirement is based on [Section 5.3.4](https://www.rfc-editor.org/rfc/rfc7518#section-5.3.4) (Security Effect of the HMAC
> Key) of NIST SP 800-117 [[NIST.800-107](https://www.rfc-editor.org/rfc/rfc7518#ref-NIST.800-107)], which states that the
> effective security strength is the minimum of the security strength
> of the key and two times the size of the internal hash value.)
Adding to this: optimum key length is equal to block size (not greater). From [The Wikipedia Page](https://en.wikipedia.org/wiki/HMAC) pseudocode:
```
// Keys longer than blockSize are shortened by hashing them
if (length(key) > blockSize) then
key = hash(key)
// Keys shorter than blockSize are padded to blockSize by padding with zeros on the right
if (length(key) < blockSize) then
return Pad(key, blockSize) // Pad key with zeros to make it blockSize bytes long
```
So, by matching signing secret to block size, we avoid padding with non-random numbers (zeroes) and we avoid hashing our key.
## Why Base64 Encoded?
From [the golang-jwt/jwt FAQ](https://golang-jwt.github.io/jwt/usage/signing_methods/#frequently-asked-questions):
> We often get asked why the HMAC signing method only supports []byte and not string. This is intentionally and there are different reasons for doing so. First, we aim to use the key type that the underlying cryptographic operation in the Go library uses (this also applies to the other signing methods). In case of HMAC, this is hmac.New and it uses []byte as the type to represent a key.
>
> Second, using string as a key type to represent a symmetric key can lead to unwanted situations. It gives the impression that this is something 'human readable' (like a password), but it is not. A symmetric key should contain as much entropy as possible and therefore include characters from the whole character set (even 'unreadable' ones) and ideally be generated by a cryptographic random source, such as rand.Read. Signing tokens with a cryptographically weak key will compromise the security of the tokens and in effect everything that depends on it, e.g., user authentication.
>
> If you have trouble handling a []byte key in our setup, e.g., because you are reading it from your environment variables on your cluster or similar, you can always use base64 encoding to have the key as a "string" type outside of your program and then use base64.Encoding.DecodeString to decode the base64 string into the []byte slice that the signing method needs.
In many projects, I am exposing my signing secrets to my APIs via secret managers as environment variables. So it makes sense to have them be base64-encoded strings. A quick cheatsheet on how to get a base64-encoded string as a byte array from an environment variable:
```go
signingSecret, err := base64.StdEncoding.DecodeString(os.Getenv("MY_SIGNING_SECRET"))
if err != nil {
// Handle error
}
// signingSecret is ready to use
```