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>
85
JWT.md
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())
|
||||
|
||||
Reference in New Issue
Block a user