MCPcopy Create free account
hub / github.com/Mnexa-AI/e2a / HandleCreateAPIKey

Method HandleCreateAPIKey

internal/auth/auth.go:749–820  ·  view source on GitHub ↗

HandleCreateAPIKey creates a new API key for the authenticated user.

(w http.ResponseWriter, r *http.Request)

Source from the content-addressed store, hash-verified

747
748// HandleCreateAPIKey creates a new API key for the authenticated user.
749func (ua *UserAuth) HandleCreateAPIKey(w http.ResponseWriter, r *http.Request) {
750 user := ua.AuthenticateRequest(r)
751 if user == nil {
752 http.Error(w, "not authenticated", http.StatusUnauthorized)
753 return
754 }
755
756 var req struct {
757 Name string `json:"name"`
758 ExpiresAt *string `json:"expires_at,omitempty"` // optional ISO 8601 timestamp
759 // Scope (Slice 5a) selects the credential's blast radius. Omitted/""
760 // defaults to account (backward compatible). "agent" requires Agent to
761 // name one of the caller's agents by email; the minted key can act ONLY
762 // as that agent.
763 Scope string `json:"scope,omitempty"`
764 Agent string `json:"agent,omitempty"` // agent email, required when scope=agent
765 }
766 json.NewDecoder(r.Body).Decode(&req)
767
768 // Parse optional expires_at. Empty string and missing field both mean
769 // "never expires" — symmetric with the NULL column default. Malformed
770 // or already-past timestamps are client errors, not "use NULL silently."
771 var expiresAt *time.Time
772 if req.ExpiresAt != nil && *req.ExpiresAt != "" {
773 t, err := time.Parse(time.RFC3339, *req.ExpiresAt)
774 if err != nil {
775 http.Error(w, "expires_at must be an RFC 3339 timestamp", http.StatusBadRequest)
776 return
777 }
778 if !t.After(time.Now()) {
779 http.Error(w, "expires_at must be in the future", http.StatusBadRequest)
780 return
781 }
782 expiresAt = &t
783 }
784
785 // Default to an account-scoped key (the pre-Slice-5a behavior). When the
786 // caller asks for an agent-scoped key, resolve the named agent to its id —
787 // CreateScopedAPIKey re-checks ownership, so a wrong/foreign agent is
788 // rejected rather than minting an over-broad or cross-tenant key.
789 scope := req.Scope
790 if scope == "" {
791 scope = identity.ScopeAccount
792 }
793 if !identity.ValidScope(scope) {
794 http.Error(w, "scope must be 'account' or 'agent'", http.StatusBadRequest)
795 return
796 }
797 var agentID string
798 if scope == identity.ScopeAgent {
799 if req.Agent == "" {
800 http.Error(w, "agent (email) is required when scope=agent", http.StatusBadRequest)
801 return
802 }
803 ag, err := ua.store.GetAgentByEmail(r.Context(), identity.NormalizeEmail(req.Agent))
804 if err != nil || ag == nil || ag.UserID != user.ID {
805 http.Error(w, "agent not found", http.StatusBadRequest)
806 return

Calls 8

AuthenticateRequestMethod · 0.95
ValidScopeFunction · 0.92
NormalizeEmailFunction · 0.92
CreateScopedAPIKeyMethod · 0.80
writeJSONFunction · 0.70
GetAgentByEmailMethod · 0.65
ErrorMethod · 0.45
WriteHeaderMethod · 0.45