(r *http.Request)
| 695 | } |
| 696 | |
| 697 | func (a *API) authenticatePrincipal(r *http.Request) (*identity.Principal, error) { |
| 698 | authHeader := r.Header.Get("Authorization") |
| 699 | if authHeader != "" { |
| 700 | bearer := stripBearerScheme(authHeader) |
| 701 | // auth.md agent access token (Slice 5b-2): an RS256 JWT we minted, |
| 702 | // resolving to an agent-scoped principal. Checked before the API-key |
| 703 | // path since a JWT is never a valid API key. A bearer that looks like |
| 704 | // our JWT but fails verification is rejected here (not fall-through). |
| 705 | if p, ours, err := a.resolveAgentAccessToken(r, bearer); ours { |
| 706 | if err != nil { |
| 707 | return nil, err |
| 708 | } |
| 709 | return p, nil |
| 710 | } |
| 711 | if strings.HasPrefix(bearer, oauth.AccessTokenPrefix) { |
| 712 | return a.principalFromOAuthToken(r, bearer) |
| 713 | } |
| 714 | return a.store.GetPrincipalByAPIKey(r.Context(), bearer) |
| 715 | } |
| 716 | // Fall back to session cookie auth — the web dashboard owner, account scope. |
| 717 | if a.userAuth != nil { |
| 718 | if user := a.userAuth.AuthenticateRequest(r); user != nil { |
| 719 | return &identity.Principal{User: user, Scope: identity.ScopeAccount}, nil |
| 720 | } |
| 721 | } |
| 722 | return nil, fmt.Errorf("authorization required") |
| 723 | } |
| 724 | |
| 725 | // principalFromOAuthToken validates an ate2a_-prefixed bearer via fosite's |
| 726 | // IntrospectToken (which derives the signature using the same strategy that |
no test coverage detected