Keysmith

Policies

Rate limits, IP allowlists, and key lifetime constraints.

The policy subsystem provides fine-grained control over API key behavior. Attach a policy to a key to enforce rate limits, restrict IP addresses, limit origins, and set maximum key lifetimes.

Creating a policy

pol, err := eng.CreatePolicy(ctx, &policy.Policy{
    Name:           "Standard API",
    RateLimit:      1000,
    RateWindow:     time.Minute,
    AllowedIPs:     []string{"10.0.0.0/8", "172.16.0.0/12"},
    AllowedOrigins: []string{"https://app.example.com"},
    AllowedScopes:  []string{"read:users", "write:users"},
    MaxKeyAge:      90 * 24 * time.Hour,
})

Policy fields

FieldTypeDescription
NamestringHuman-readable policy name
RateLimitintMaximum requests per window (0 = unlimited)
RateWindowtime.DurationRate limit window duration
AllowedIPs[]stringCIDR-notation IP allowlist (empty = all allowed)
AllowedOrigins[]stringHTTP origin allowlist (empty = all allowed)
AllowedScopes[]stringScopes this policy permits
MaxKeyAgetime.DurationMaximum key lifetime (0 = no limit)

Attaching a policy to a key

Attach a policy at key creation time:

result, err := eng.CreateKey(ctx, &keysmith.CreateKeyInput{
    Name:     "Rate-Limited Key",
    PolicyID: &policyID,
})

Policy enforcement during validation

When a key with an attached policy is validated, the engine checks:

  1. Rate limit -- If RateLimit > 0 and a RateLimiter is configured, the engine checks whether the key has exceeded its rate limit.
  2. IP allowlist -- If AllowedIPs is non-empty, the request IP must match one of the CIDR ranges.
  3. Origin allowlist -- If AllowedOrigins is non-empty, the request origin must match.
  4. Key age -- If MaxKeyAge > 0, the key must not exceed the maximum age.

Policy violations return ErrPolicyViolation.

Updating and deleting policies

// Update
pol.RateLimit = 2000
err := eng.UpdatePolicy(ctx, pol)

// Delete
err := eng.DeletePolicy(ctx, policyID)

Policy store interface

type Store interface {
    Create(ctx context.Context, p *Policy) error
    GetByID(ctx context.Context, id id.PolicyID) (*Policy, error)
    List(ctx context.Context, filter *ListFilter) ([]*Policy, error)
    Update(ctx context.Context, p *Policy) error
    Delete(ctx context.Context, id id.PolicyID) error
}

On this page