Mint and verify short-lived RS256 user tokens.

ExApps sign after AppAPI auth; Microservices check a static public key or an OIDC issuer and forward the same bearer.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-28 14:03:52 +02:00
co-authored by Cursor
parent 92feaa6915
commit f082561cc6
13 changed files with 1091 additions and 0 deletions
+48
View File
@@ -0,0 +1,48 @@
package usertoken
import (
"context"
"errors"
)
// ErrUnauthorized is wrapped by every failed token check.
// Startup and configuration failures do not wrap it.
var ErrUnauthorized = errors.New("unauthorized")
// Caller is the user a verified token names.
// Groups is nil when the token omitted the claim, and non-nil (possibly empty)
// when the claim was present.
type Caller struct {
Subject string
Username string
Groups []string
}
type ctxKey int
const (
ctxCaller ctxKey = iota
ctxBearer
)
// CallerFromContext returns the user [Auth.Middleware] stored.
func CallerFromContext(ctx context.Context) (Caller, bool) {
c, ok := ctx.Value(ctxCaller).(Caller)
return c, ok
}
// BearerFromContext returns the raw JWT [Auth.Middleware] stored, without the
// "Bearer " prefix. Outbound calls send "Bearer " plus this string.
func BearerFromContext(ctx context.Context) (string, bool) {
s, ok := ctx.Value(ctxBearer).(string)
return s, ok
}
func withAuth(ctx context.Context, c Caller, raw string) context.Context {
ctx = context.WithValue(ctx, ctxCaller, c)
return context.WithValue(ctx, ctxBearer, raw)
}
func unauthorized(msg string) error {
return errors.Join(errors.New(msg), ErrUnauthorized)
}