package auth import ( "os" "path/filepath" "testing" "time" ) func TestVerify_ValidToken(t *testing.T) { v := NewVerifier([]byte("test-secret"), nil) tok, _ := Issue([]byte("test-secret"), "alice", "tunnel", time.Hour) claims, err := v.Verify(tok) if err != nil { t.Fatalf("expected ok, got %v", err) } if claims.Subject != "alice" || claims.Scope != "tunnel" { t.Errorf("claims wrong: %+v", claims) } } func TestVerify_WrongSecret(t *testing.T) { v := NewVerifier([]byte("server-secret"), nil) tok, _ := Issue([]byte("attacker-secret"), "eve", "tunnel", time.Hour) if _, err := v.Verify(tok); err == nil { t.Fatal("expected verification fail") } } func TestVerify_Expired(t *testing.T) { v := NewVerifier([]byte("test-secret"), nil) tok, _ := Issue([]byte("test-secret"), "alice", "tunnel", -time.Minute) if _, err := v.Verify(tok); err == nil { t.Fatal("expected expired") } } func TestVerify_WrongScope(t *testing.T) { v := NewVerifier([]byte("test-secret"), nil) tok, _ := Issue([]byte("test-secret"), "alice", "read-only", time.Hour) if _, err := v.Verify(tok); err == nil { t.Fatal("expected scope mismatch") } } func TestVerify_RevokedJTI(t *testing.T) { revoked := map[string]bool{"abc123": true} v := NewVerifier([]byte("test-secret"), revoked) tok, _ := IssueWithJTI([]byte("test-secret"), "alice", "tunnel", time.Hour, "abc123") if _, err := v.Verify(tok); err == nil { t.Fatal("expected revoked") } } func TestLoadRevokedFile_Missing(t *testing.T) { m, err := LoadRevokedFile(filepath.Join(t.TempDir(), "nonexistent")) if err != nil { t.Fatal(err) } if len(m) != 0 { t.Errorf("expected empty, got %v", m) } } func TestLoadRevokedFile_ParsesEntries(t *testing.T) { tmp := filepath.Join(t.TempDir(), "r.txt") os.WriteFile(tmp, []byte("# comment\nabc\n\nxyz\n"), 0644) m, err := LoadRevokedFile(tmp) if err != nil { t.Fatal(err) } if !m["abc"] || !m["xyz"] || len(m) != 2 { t.Errorf("got %v", m) } }