HWT (Hewo Web Token)

A dead simple, Secure by design alternative to JSON Web Token (JWT)
import (
"crypto/rand"
"fmt"
"codeberg.org/Yonle/hwt"
)
func main() {
var payload []byte // could be anything. stringified json, or whatever, you name it.
// for this example, let's say our payload is just "OMG HI"
payload = []byte("OMG HI")
salt := make([]byte, 32) // random bytes for salting. you may store this safely to be then reused later.
_, err := rand.Read(salt) // feed random bytes to salt.
if err != nil {
panic(err)
}
token := hwt.Sign(payload, salt)
fmt.Println("Token:", token)
// Output:
// Token: abcdefg12345.abcdefg12345
// now let's verify
payload, ok := hwt.Check(token, salt)
if !ok {
// it's not valid.
panic("Token not valid!")
}
// now read the payload
fmt.Println("Payload:", string(payload))
// Output:
// Payload: OMG HI
}
Why?
- JWT took 5 layers of encoding (Base64 ×3 + JSON ×3) for something that should be one hash and a concatenation.
- The
header
on JWT token is often redundant in many usecases.
What HWT do?
- The format:
<payload>.<sig>
. That's it.
- It just hash a bytes of
<payload>
with HMAC+SHA256 (+ salt)
- Then encode the
<payload>
and <sig>
into base64 string, Resulting <base64encoded_payload>.<base64encoded_hash>
That's it for the process of token making.
For checking process:
- It split the token into 2 parts
- It decode the base64 as a bytes for both
<payload>
and <sig>
- It tries to hash a bytes of
<payload>
with our salt, Then compares it with <sig>
. If it's the same, That's us! Now read the <payload>
. If it's not, It's invalid, and we shouldn't read the payload (unless you wanna see the data out of curiosity)
That's it for the process of validating. Additional ones like expiry
or whatever it is? Validate that yourself.
Where should i put the token on?
It's recommended to store the token as a cookie. When sending cookie containing token to the client, Send Set-Cookie
with Secure
, HttpOnly
, and SameSite
flags.
Set-Cookie: hwt_token=<token>; HttpOnly; Secure; SameSite=Strict; Path=/