Update JWT documentation with correct API usage

- Updated all examples to use jwt.NewDBConnection() wrapper
- Fixed transaction handling to use gen.dbConn.BeginTx()
- Removed references to obsolete jwt.NewSQLExecutor()
- Added missing context imports
- Fixed variable naming in complete example
- Corrected DBConn type from *sql.DB to DBConnection interface

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-11 16:54:58 +11:00
parent f1799917d8
commit 282b1f3d74

85
JWT.md

@@ -47,7 +47,7 @@ func main() {
FreshExpireAfter: 5, // Tokens stay fresh for 5 minutes
TrustedHost: "example.com",
SecretKey: "your-secret-key-here",
DBConn: db,
DBConn: jwt.NewDBConnection(db),
DBType: jwt.DatabaseType{
Type: jwt.DatabasePostgreSQL,
Version: "15",
@@ -59,6 +59,7 @@ func main() {
}
// Generate tokens
userID := 42
accessToken, accessExp, err := gen.NewAccess(userID, true, false)
refreshToken, refreshExp, err := gen.NewRefresh(userID, false)
}
@@ -91,7 +92,7 @@ type GeneratorConfig struct {
SecretKey string // Secret key for token signing
// Optional fields (for database support)
DBConn *sql.DB // Database connection (nil to disable revocation)
DBConn DBConnection // Database connection (nil to disable revocation)
DBType DatabaseType // Database type and version
TableConfig TableConfig // Table configuration
}
@@ -161,24 +162,23 @@ token, expiry, err := gen.NewRefresh(42, true)
Tokens must be validated within a transaction context:
```go
import "context"
// Begin transaction
tx, err := db.Begin()
tx, err := gen.dbConn.BeginTx(context.Background(), nil)
if err != nil {
return err
}
defer tx.Rollback()
// Create executor
exec := jwt.NewSQLExecutor(tx)
// Validate access token
token, err := gen.ValidateAccess(exec, tokenString)
token, err := gen.ValidateAccess(tx, tokenString)
if err != nil {
return err // Token invalid or revoked
}
// Validate refresh token
token, err := gen.ValidateRefresh(exec, tokenString)
refreshToken, err := gen.ValidateRefresh(tx, tokenString)
if err != nil {
return err // Token invalid or revoked
}
@@ -209,19 +209,19 @@ ttl := token.TTL // "session" or "exp"
### Revoking a Token
```go
tx, _ := db.Begin()
import "context"
tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
defer tx.Rollback()
exec := jwt.NewSQLExecutor(tx)
// Validate token first
token, err := gen.ValidateAccess(exec, tokenString)
token, err := gen.ValidateAccess(tx, tokenString)
if err != nil {
return err
}
// Revoke the token
err = token.Revoke(exec)
err = token.Revoke(tx)
if err != nil {
return err
}
@@ -232,7 +232,7 @@ tx.Commit()
### Checking Revocation Status
```go
isValid, err := token.CheckNotRevoked(exec)
isValid, err := token.CheckNotRevoked(tx)
if !isValid {
// Token has been revoked
}
@@ -247,12 +247,17 @@ Tokens can be marked as "fresh" for sensitive operations:
accessToken, _, _ := gen.NewAccess(userID, true, false) // fresh=true
// Check freshness
token, _ := gen.ValidateAccess(exec, accessToken)
tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
defer tx.Rollback()
token, _ := gen.ValidateAccess(tx, accessToken)
currentTime := time.Now().Unix()
if currentTime > token.Fresh {
// Token is stale, require re-authentication
return errors.New("token is not fresh")
}
tx.Commit()
```
## Cleanup
@@ -358,7 +363,10 @@ CREATE INDEX IF NOT EXISTS idx_jwtblacklist_sub ON jwtblacklist(sub);
### GORM
```go
import "gorm.io/gorm"
import (
"context"
"gorm.io/gorm"
)
// Get underlying *sql.DB from GORM
gormDB, _ := gorm.Open(postgres.Open(dsn), &gorm.Config{})
@@ -367,21 +375,25 @@ sqlDB, _ := gormDB.DB()
// Create generator with sql.DB
gen, _ := jwt.CreateGenerator(jwt.GeneratorConfig{
// ... config
DBConn: sqlDB,
DBConn: jwt.NewDBConnection(sqlDB),
})
// Use with transactions
tx := gormDB.Begin()
sqlTx, _ := tx.DB()
exec := jwt.NewSQLExecutor(sqlTx)
token, _ := gen.ValidateAccess(exec, tokenString)
tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
defer tx.Rollback()
token, _ := gen.ValidateAccess(tx, tokenString)
tx.Commit()
```
### Bun
```go
import "github.com/uptrace/bun"
import (
"context"
"github.com/uptrace/bun"
)
// Get underlying *sql.DB from Bun
bunDB := bun.NewDB(sqldb, pgdialect.New())
@@ -390,14 +402,15 @@ sqlDB := bunDB.DB // Already *sql.DB
// Create generator
gen, _ := jwt.CreateGenerator(jwt.GeneratorConfig{
// ... config
DBConn: sqlDB,
DBConn: jwt.NewDBConnection(sqlDB),
})
// Use with transactions
tx, _ := bunDB.Begin()
sqlTx, _ := tx.DB()
exec := jwt.NewSQLExecutor(sqlTx)
token, _ := gen.ValidateAccess(exec, tokenString)
tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
defer tx.Rollback()
token, _ := gen.ValidateAccess(tx, tokenString)
tx.Commit()
```
@@ -431,7 +444,7 @@ func main() {
FreshExpireAfter: 5,
TrustedHost: "example.com",
SecretKey: "super-secret-key",
DBConn: db,
DBConn: jwt.NewDBConnection(db),
DBType: jwt.DatabaseType{
Type: jwt.DatabasePostgreSQL,
Version: "15",
@@ -457,10 +470,10 @@ func main() {
fmt.Printf("Refresh Token: %s (expires: %d)\n", refreshToken, refreshExp)
// Validate access token
tx, _ := db.Begin()
exec := jwt.NewSQLExecutor(tx)
tx, _ := gen.dbConn.BeginTx(context.Background(), nil)
defer tx.Rollback()
token, err := gen.ValidateAccess(exec, accessToken)
token, err := gen.ValidateAccess(tx, accessToken)
if err != nil {
panic(err)
}
@@ -468,7 +481,7 @@ func main() {
fmt.Printf("Token valid for user: %d\n", token.SUB)
// Revoke token
err = token.Revoke(exec)
err = token.Revoke(tx)
if err != nil {
panic(err)
}
@@ -476,15 +489,15 @@ func main() {
tx.Commit()
// Try to validate revoked token
tx, _ = db.Begin()
exec = jwt.NewSQLExecutor(tx)
tx2, _ := gen.dbConn.BeginTx(context.Background(), nil)
defer tx2.Rollback()
_, err = gen.ValidateAccess(exec, accessToken)
_, err = gen.ValidateAccess(tx2, accessToken)
if err != nil {
fmt.Println("Token is revoked:", err)
}
tx.Commit()
tx2.Commit()
// Cleanup expired tokens
err = gen.Cleanup(context.Background())