tauth
tauth issues HS256 JWT access tokens and opaque refresh tokens. With the refresh token you can recreate the access token and keep a session alive (tauth does not maintain sessions, only keeps tokens stored in memory/database, for now)
go get github.com/atomicswe/tauth
Requires Go 1.25 or later.
Disclaimer
This package was made with my specific needs in mind, so it likely won't have all the features someone needs. If that's the case, follow the contributing section to know more.
Storage types
tauth currently offers two storage types: in-memory storage and database storage (currently only Postgres).
In-memory storage
This is the first storage option tauth offers, and also the simplest one. When using this storage type all the tokens are stored in memory using a map.
This storage type has some limitations, like for example, the high likeliness of having out-of-sync data between two pods of a service using tauth, which could cause authentication to succeed when a request is routed through a specific pod, and fail when routed through the other one.
Database storage
This is the second storage option currently available in tauth. Here all the tokens are persisted to the database that the service uses.
However, tauth currently only supports Postgres, so if your service does not use Postgres, you won't be able to use this option for now (see contributing).
Configuration
To configure which storage type tauth will use you will have to set some env vars. Here's a table describing them:
| Env variable |
Required |
Description |
TAUTH_STORAGE |
yes |
Which storage type to use (in_memory,database) |
TAUTH_DB_CONNECTION |
yes, when using database |
The database connection string |
TAUTH_DB_DRIVER |
yes, when using database |
The database driver to use (pgx) |
Configuration
| Env variable |
Required |
Description |
TAUTH_SECRET_KEY |
yes |
HMAC secret used to sign and validate access tokens |
TAUTH_ISS |
no |
JWT issuer. Defaults to tauth-default-iss |
Usage
Issue tokens
All options are optional. Access tokens default to 5 minutes, refresh tokens to 24 hours. Access tokens must be at least 5 minutes. Refresh tokens must be at least 1 hour.
package main
import (
"fmt"
"time"
"github.com/atomicswe/tauth"
)
func main() {
atExp := 15 * time.Minute
rtExp := 48 * time.Hour
tokens, err := tauth.IssueTokens("alice", tauth.TAuthOptions{
ATExpiration: &atExp,
RTExpiration: &rtExp,
CustomClaims: `{"role":"admin"}`,
})
if err != nil {
panic(err)
}
fmt.Println(tokens.AccessToken.Token)
fmt.Println(tokens.RefreshToken.Token)
}
user is stored in the JWT user claim and used as the storage key. Issuing again for the same user replaces the previously stored tokens.
Validate an access token
user, customClaims, err := tauth.ValidateToken(tokens.AccessToken.Token)
if err != nil {
panic(err)
}
fmt.Println(user, customClaims)
Validation checks the signature, issuer, and expiry. It does not look up the stored tokens.
Refresh tokens
refreshed, err := tauth.RefreshTokens("alice", tokens.RefreshToken.Token)
if err != nil {
panic(err)
}
The new pair reuses the previous lifetimes and custom claims, and replaces the stored tokens for that user.
Errors
Sentinel errors live in pkg/terrors:
import (
"errors"
"github.com/atomicswe/tauth/pkg/terrors"
)
if errors.Is(err, terrors.TErrSecretKeyMissing) {
// TAUTH_SECRET_KEY is not set
}
Contributing
Issues and pull requests are welcome.
Branch from main, add tests for new behavior, and run the test suite:
make test
Then open a pull request against main. If you do not have write access, GitHub will create the branch from a fork automatically.
Use Go 1.25 or later. Please discuss breaking changes to the public API in an issue first.