package jwtauth import "context" type Claims struct { UserID string Groups []string // JTI and Scopes are populated only for HS256 shortcut tokens; a full OIDC / // dev session leaves them empty. A non-empty JTI marks a *scoped* token — // one allowed to reach only the endpoints its Scopes grant (the route layer // enforces this). This keeps a leaked shortcut token's blast radius minimal. JTI string Scopes []string } // Scoped reports whether these claims came from a scoped shortcut token rather // than a full login session. func (c *Claims) Scoped() bool { return c.JTI != "" } // HasScope reports whether the claims grant the named scope. func (c *Claims) HasScope(scope string) bool { for _, s := range c.Scopes { if s == scope { return true } } return false } type ctxKey int const ( claimsCtxKey ctxKey = iota deviceCtxKey deviceTypeCtxKey ) func ClaimsFromContext(ctx context.Context) (*Claims, bool) { c, ok := ctx.Value(claimsCtxKey).(*Claims) return c, ok } func DeviceNameFromContext(ctx context.Context) (string, bool) { n, ok := ctx.Value(deviceCtxKey).(string) return n, ok } // DeviceTypeFromContext returns the client-declared device type set by the auth // middleware (browser / macos / windows / linux), defaulting to "browser". func DeviceTypeFromContext(ctx context.Context) string { t, ok := ctx.Value(deviceTypeCtxKey).(string) if !ok || t == "" { return "browser" } return t }