feat(backend): update JWT auth implementation and tests
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -14,18 +14,45 @@ package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"crussell/db"
|
||||
"crussell/testutils/testdb"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
InitJWT("test-secret-key-for-jwt-test")
|
||||
|
||||
pool, err := testdb.NewPool("")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "WARN: No test DB available — JTI revocation tests will fail: %v\n", err)
|
||||
} else {
|
||||
// Run migration to ensure the revoked_jtis and refresh_tokens tables exist
|
||||
testdb.Migrate(&testing.T{}, pool)
|
||||
db.DB = pool
|
||||
}
|
||||
|
||||
code := m.Run()
|
||||
if pool != nil {
|
||||
pool.Close()
|
||||
}
|
||||
os.Exit(code)
|
||||
}
|
||||
|
||||
// requiresDB skips the test if the database is not available (e.g. running
|
||||
// tests standalone without test DB setup). DB-backed JTI revocation tests
|
||||
// need a connection to the revoked_jtis table.
|
||||
func requiresDB(t *testing.T) {
|
||||
t.Helper()
|
||||
if db.DB == nil {
|
||||
t.Skip("skipping: no database connection")
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// generateJTI Tests
|
||||
// =============================================================================
|
||||
@@ -158,6 +185,7 @@ func TestVerifyToken_ReturnsJTI(t *testing.T) {
|
||||
// TestVerifyToken_RevokedJTI creates a token, revokes its JTI, and verifies
|
||||
// that VerifyToken returns an error containing "token revoked".
|
||||
func TestVerifyToken_RevokedJTI(t *testing.T) {
|
||||
requiresDB(t)
|
||||
token, jti, err := GenerateToken("user-004", "verified_email")
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken() failed: %v", err)
|
||||
@@ -203,6 +231,7 @@ func TestVerifyToken_MissingJTI(t *testing.T) {
|
||||
// TestRevokeJTI_AddsToSet verifies that calling RevokeJTI adds the JTI to the
|
||||
// revoked set, and IsJTIRevoked returns true for it.
|
||||
func TestRevokeJTI_AddsToSet(t *testing.T) {
|
||||
requiresDB(t)
|
||||
_, jti, err := GenerateToken("user-006", "verified_email")
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken() failed: %v", err)
|
||||
@@ -234,16 +263,24 @@ func TestIsJTIRevoked_NonExistent(t *testing.T) {
|
||||
// TestCleanupRevokedJTIs_RemovesExpired adds a JTI with a past expiry time,
|
||||
// runs CleanupRevokedJTIs, and verifies the JTI is removed from the set.
|
||||
func TestCleanupRevokedJTIs_RemovesExpired(t *testing.T) {
|
||||
requiresDB(t)
|
||||
_, jti, err := GenerateToken("user-007", "verified_email")
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken() failed: %v", err)
|
||||
}
|
||||
|
||||
// Add with past expiry (1 hour ago)
|
||||
RevokeJTI(jti, time.Now().Add(-1*time.Hour))
|
||||
// Add with future expiry so IsJTIRevoked sees it
|
||||
RevokeJTI(jti, time.Now().Add(1*time.Hour))
|
||||
|
||||
if !IsJTIRevoked(jti) {
|
||||
t.Fatal("JTI should be in revoked set before cleanup")
|
||||
t.Fatal("JTI should be in revoked set after RevokeJTI")
|
||||
}
|
||||
|
||||
// Directly update the DB to set expiry in the past
|
||||
_, err = db.DB.Exec(context.Background(),
|
||||
"UPDATE revoked_jtis SET expires_at = NOW() - INTERVAL '1 hour' WHERE jti = $1", jti)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to expire JTI: %v", err)
|
||||
}
|
||||
|
||||
CleanupRevokedJTIs()
|
||||
@@ -256,6 +293,7 @@ func TestCleanupRevokedJTIs_RemovesExpired(t *testing.T) {
|
||||
// TestCleanupRevokedJTIs_KeepsValid adds a JTI with a future expiry time,
|
||||
// runs CleanupRevokedJTIs, and verifies the JTI is still in the set.
|
||||
func TestCleanupRevokedJTIs_KeepsValid(t *testing.T) {
|
||||
requiresDB(t)
|
||||
_, jti, err := GenerateToken("user-008", "verified_email")
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken() failed: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user