Keysmith

Scopes

Hierarchical permission scopes for API keys.

The scope subsystem manages permission scopes that can be assigned to API keys. Scopes follow a hierarchical naming convention (e.g., read:users, write:users:email).

Creating scopes

scp, err := eng.CreateScope(ctx, &scope.Scope{
    Name:        "read:users",
    Description: "Read user profiles",
})

Assigning scopes to keys

Scopes can be assigned at key creation time or added later:

// At creation
result, err := eng.CreateKey(ctx, &keysmith.CreateKeyInput{
    Name:   "User API Key",
    Scopes: []string{"read:users", "write:users"},
})

// Add scopes later
err := eng.AssignScopes(ctx, keyID, []string{"read:billing"})

// Remove scopes
err := eng.RemoveScopes(ctx, keyID, []string{"write:users"})

Checking scopes during validation

After validating a key, check that it has the required scopes:

vr, err := eng.ValidateKey(ctx, rawKey)
if err != nil {
    return err
}

// Check for a specific scope
hasScope := false
for _, s := range vr.Scopes {
    if s == "write:users" {
        hasScope = true
        break
    }
}

Or use the middleware for automatic scope checking:

import "github.com/xraph/keysmith/middleware"

// Require specific scopes on a route
mw := middleware.RequireScopes("read:users", "write:users")

Listing scopes

scopes, err := eng.ListScopes(ctx, &scope.ListFilter{
    Limit:  100,
    Offset: 0,
})

Scope store interface

type Store interface {
    Create(ctx context.Context, s *Scope) error
    GetByID(ctx context.Context, id id.ScopeID) (*Scope, error)
    List(ctx context.Context, filter *ListFilter) ([]*Scope, error)
    Delete(ctx context.Context, id id.ScopeID) error
    AssignToKey(ctx context.Context, keyID id.KeyID, scopeNames []string) error
    RemoveFromKey(ctx context.Context, keyID id.KeyID, scopeNames []string) error
    GetByKeyID(ctx context.Context, keyID id.KeyID) ([]*Scope, error)
    ListByNames(ctx context.Context, names []string) ([]*Scope, error)
}

On this page