// Package token validates incoming Bearer tokens and extracts the subject // (client agent identity). Prod uses Pocket ID JWKS; dev uses a static table. package token import ( "context" "errors" "net/http" "strings" ) // ErrInvalid is returned when a bearer token cannot be parsed or verified. var ErrInvalid = errors.New("token: invalid or missing bearer token") // Validator turns a raw bearer string into the authenticated client subject // (the Pocket ID `sub` claim, i.e. the client/agent identity). type Validator interface { Validate(ctx context.Context, bearer string) (subject string, err error) } // Static is a dev-mode validator that accepts a fixed set of bearers → subjects. type Static map[string]string func (s Static) Validate(_ context.Context, bearer string) (string, error) { if bearer == "" { return "", ErrInvalid } sub, ok := s[bearer] if !ok { return "", ErrInvalid } return sub, nil } // PocketID is a stub for a JWKS-based Pocket ID token verifier. type PocketID struct{} func (PocketID) Validate(_ context.Context, _ string) (string, error) { return "", errors.New("token.PocketID: not wired yet (follow-up subtask)") } // FromAuthHeader extracts the bearer from an "Authorization: Bearer …" header. func FromAuthHeader(r *http.Request) (string, error) { h := r.Header.Get("Authorization") const prefix = "Bearer " if !strings.HasPrefix(h, prefix) { return "", ErrInvalid } return strings.TrimPrefix(h, prefix), nil }