MCPcopy Create free account
hub / github.com/Harshitk-cp/engram / SessionOrAPIKey

Function SessionOrAPIKey

internal/api/middleware/auth.go:84–125  ·  view source on GitHub ↗

SessionOrAPIKey authenticates a request via the console session cookie first, then falls back to a Bearer API key. Both resolve to a *domain.APIKeyAuth in the request context, so all /v1 handlers work for the browser console and for programmatic clients without any per-handler changes.

(apiKeyStore domain.APIKeyStore, resolver SessionResolver, allowedOrigins []string)

Source from the content-addressed store, hash-verified

82// the request context, so all /v1 handlers work for the browser console and for
83// programmatic clients without any per-handler changes.
84func SessionOrAPIKey(apiKeyStore domain.APIKeyStore, resolver SessionResolver, allowedOrigins []string) func(http.Handler) http.Handler {
85 allowAll := len(allowedOrigins) == 1 && allowedOrigins[0] == "*"
86 allowed := make(map[string]bool, len(allowedOrigins))
87 for _, o := range allowedOrigins {
88 allowed[o] = true
89 }
90
91 return func(next http.Handler) http.Handler {
92 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
93 if resolver != nil {
94 if c, err := r.Cookie(SessionCookieName); err == nil && c.Value != "" {
95 if auth, err := resolver.ResolveSessionAuth(r.Context(), c.Value); err == nil && auth != nil {
96 if isStateChanging(r.Method) && !originAllowed(r, allowed, allowAll) {
97 writeError(w, http.StatusForbidden, "cross-origin request blocked")
98 return
99 }
100 next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), authContextKey, auth)))
101 return
102 }
103 }
104 }
105
106 authHeader := r.Header.Get("Authorization")
107 if authHeader == "" {
108 writeError(w, http.StatusUnauthorized, "missing authorization")
109 return
110 }
111 parts := strings.SplitN(authHeader, " ", 2)
112 if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") {
113 writeError(w, http.StatusUnauthorized, "invalid authorization header format")
114 return
115 }
116 auth, err := apiKeyStore.GetAuthByHash(r.Context(), HashAPIKey(parts[1]))
117 if err != nil {
118 writeError(w, http.StatusUnauthorized, "invalid API key")
119 return
120 }
121 go func() { _ = apiKeyStore.UpdateLastUsed(context.Background(), auth.KeyID) }()
122 next.ServeHTTP(w, r.WithContext(context.WithValue(r.Context(), authContextKey, auth)))
123 })
124 }
125}
126
127// RequireScope returns middleware that rejects requests whose API key lacks the given scope.
128// Keys with the "admin" scope pass all scope checks.

Callers

nothing calls this directly

Calls 8

isStateChangingFunction · 0.85
originAllowedFunction · 0.85
HashAPIKeyFunction · 0.85
writeErrorFunction · 0.70
ResolveSessionAuthMethod · 0.65
GetMethod · 0.65
GetAuthByHashMethod · 0.65
UpdateLastUsedMethod · 0.65

Tested by

no test coverage detected