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

Method CreateScopedAPIKey

internal/identity/store.go:3397–3450  ·  view source on GitHub ↗

CreateScopedAPIKey issues a fresh API key with an explicit scope (Slice 5a). - ScopeAccount: account-wide admin; agentID must be empty; prefix e2a_acct_. - ScopeAgent: bound to agentID (which must be a non-empty agent owned by the user); prefix e2a_agt_. The key can only act as that one agent. The

(ctx context.Context, userID, name, scope, agentID string, expiresAt *time.Time)

Source from the content-addressed store, hash-verified

3395// The visible prefix makes a key's blast radius obvious at a glance, and the DB
3396// CHECK (scope='agent') == (agent_id IS NOT NULL) backstops the binding.
3397func (s *Store) CreateScopedAPIKey(ctx context.Context, userID, name, scope, agentID string, expiresAt *time.Time) (*APIKey, error) {
3398 if !ValidScope(scope) {
3399 return nil, fmt.Errorf("invalid credential scope %q", scope)
3400 }
3401 if scope == ScopeAgent && agentID == "" {
3402 return nil, fmt.Errorf("agent-scoped key requires an agent_id")
3403 }
3404 if scope == ScopeAccount && agentID != "" {
3405 return nil, fmt.Errorf("account-scoped key must not name an agent")
3406 }
3407 // For an agent-scoped key, the named agent must exist and be owned by the
3408 // same user — otherwise a caller could mint a key bound to someone else's
3409 // agent (the FK alone wouldn't catch cross-user binding).
3410 if scope == ScopeAgent {
3411 owns, err := s.userOwnsAgent(ctx, agentID, userID)
3412 if err != nil {
3413 return nil, err
3414 }
3415 if !owns {
3416 return nil, fmt.Errorf("agent %q not found or not owned by user", agentID)
3417 }
3418 }
3419
3420 id := "apk_" + generateID()
3421 plaintext := generateAPIKey(scope)
3422 keyHash := hashAPIKey(plaintext)
3423 // Show the scoped prefix + a few key chars (e.g. "e2a_agt_abcd…").
3424 prefix := plaintext[:16]
3425 now := time.Now()
3426 var agentCol *string
3427 if scope == ScopeAgent {
3428 agentCol = &agentID
3429 }
3430 ak := &APIKey{
3431 ID: id,
3432 UserID: userID,
3433 Name: name,
3434 KeyPrefix: prefix,
3435 PlaintextKey: plaintext,
3436 CreatedAt: now,
3437 Scope: scope,
3438 AgentID: agentCol,
3439 ExpiresAt: expiresAt,
3440 }
3441 _, err := s.pool.Exec(ctx,
3442 `INSERT INTO api_keys (id, user_id, name, key_prefix, key_hash, scope, agent_id, created_at, expires_at)
3443 VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
3444 ak.ID, ak.UserID, ak.Name, ak.KeyPrefix, keyHash, ak.Scope, agentCol, ak.CreatedAt, ak.ExpiresAt,
3445 )
3446 if err != nil {
3447 return nil, err
3448 }
3449 return ak, nil
3450}
3451
3452// userOwnsAgent reports whether agentID exists and is owned by userID.
3453func (s *Store) userOwnsAgent(ctx context.Context, agentID, userID string) (bool, error) {

Callers 6

CreateAPIKeyMethod · 0.95
newAgentIDFixtureFunction · 0.95
handleCreateAPIKeyMethod · 0.80
HandleCreateAPIKeyMethod · 0.80

Implementers 1

Storeinternal/identity/store.go

Calls 6

userOwnsAgentMethod · 0.95
ValidScopeFunction · 0.85
generateIDFunction · 0.85
generateAPIKeyFunction · 0.85
hashAPIKeyFunction · 0.85
ExecMethod · 0.65

Tested by 3

newAgentIDFixtureFunction · 0.76