Files
skills/plugins/library-navigator/skills/api-stack/api-auth/sp-api-auth/SKILL.md
2026-06-09 21:06:27 +01:00

5.3 KiB

name, description
name description
sp-api-auth Authentication-strategy meta-package for the Fetch-native API platform. Re-exports anonymous, static, bearer, and JWT strategies from standalone sibling packages, and owns the chain combinator (first-non-null-wins composition, fail-closed on throw).

@suaveplan/api-auth

Purpose

Authentication-strategy meta-package for the Suaveplan API platform. Each strategy is a factory returning a frozen SessionResolver (Request -> Principal | null) that plugs into createApi({ sessionResolver }) to populate ctx.principal before any route handler executes.

Following the api-<seam>-<plugin> extension convention, the concrete strategies live in standalone sibling packages. @suaveplan/api-auth owns the chain combinator and re-exports every strategy on identical subpaths for back-compat.

Architecture

Component Source Role
createResolverChain src/chain/chain.ts First-non-null-wins composition of SessionResolvers; fail-closed on throw
createAnonymousResolver src/anonymous/index.ts Re-export from @suaveplan/api-auth-anonymous
createStaticResolver src/static/index.ts Re-export from @suaveplan/api-auth-static
createBearerResolver src/bearer/index.ts Re-export from @suaveplan/api-auth-bearer
createJwtResolver src/jwt/index.ts Re-export from @suaveplan/api-auth-jwt
AUTH_CODES / AuthError src/error-codes/index.ts Re-export from @suaveplan/api-auth-codes

File Structure

src/
  index.ts              # Re-exports all strategies + chain + error codes
  chain/
    chain.ts            # createResolverChain implementation
    chain.test.ts       # Unit tests for chain composition
    index.ts            # Subpath barrel
  anonymous/index.ts    # Re-export barrel → @suaveplan/api-auth-anonymous
  bearer/index.ts       # Re-export barrel → @suaveplan/api-auth-bearer
  jwt/index.ts          # Re-export barrel → @suaveplan/api-auth-jwt
  static/index.ts       # Re-export barrel → @suaveplan/api-auth-static
  error-codes/index.ts  # Re-export barrel → @suaveplan/api-auth-codes

Entry Points

Import Exports
@suaveplan/api-auth All strategies + chain + AUTH_CODES + AuthError
@suaveplan/api-auth/chain createResolverChain
@suaveplan/api-auth/anonymous createAnonymousResolver
@suaveplan/api-auth/static createStaticResolver
@suaveplan/api-auth/bearer createBearerResolver
@suaveplan/api-auth/jwt createJwtResolver, defaultClaimsToPrincipal
@suaveplan/api-auth/error-codes AUTH_CODES, AuthError

Patterns

Chain composition (JWT → Bearer → Anonymous)

import { createApi } from "@suaveplan/api";
import { createJwtResolver } from "@suaveplan/api-auth/jwt";
import { createBearerResolver } from "@suaveplan/api-auth/bearer";
import { createAnonymousResolver } from "@suaveplan/api-auth/anonymous";
import { createResolverChain } from "@suaveplan/api-auth/chain";

const runtime = createApi({
    plugins: [/* ... */],
    sessionResolver: createResolverChain(
        createJwtResolver({ hmacSecret: process.env.JWT_SECRET! }),
        createBearerResolver({
            tokens: [{ token: "sk_live_abc123", principal: { id: "u_alice", scopes: ["billing:read"], claims: {} } }],
        }),
        createAnonymousResolver(),
    ),
});

Fail-closed on resolver throw

If any resolver in the chain throws, the chain re-raises AUTH.VERIFIER_FAILED wrapping the cause:

import { AUTH_CODES, AuthError } from "@suaveplan/api-auth/error-codes";

// This will throw AuthError with code AUTH_CODES.VERIFIER_FAILED
try {
    await chain.resolve(request);
} catch (err) {
    if (err instanceof AuthError && err.code === AUTH_CODES.VERIFIER_FAILED) {
        // Infrastructure failure — not an unauthenticated request
    }
}

Empty chain guard

import { createResolverChain } from "@suaveplan/api-auth/chain";

// Throws AuthError AUTH_CODES.CHAIN_EMPTY at construction
createResolverChain(); // ❌ at least one resolver required

Constraints

  • Zero runtime strategy code — all strategies are re-exports from standalone sibling packages; this package only owns createResolverChain.
  • Fail-closed — resolver throws are never swallowed; they surface as AUTH.VERIFIER_FAILED.
  • Short-circuit — the first non-null principal wins; later resolvers are not invoked.
  • Empty chain — construction with zero resolvers raises AUTH_CODES.CHAIN_EMPTY.
  • Dependencies: @suaveplan/api-auth-{anonymous,bearer,codes,jwt,static}, @suaveplan/api-types, tslib.

Error Codes

Code Raised When
AUTH.CHAIN_EMPTY createResolverChain() called with zero resolvers
AUTH.VERIFIER_FAILED A resolver in the chain threw (fail-closed)
AUTH.OPTIONS_INVALID Raised by sibling strategy packages (e.g. empty bearer table)

Checklist

  • Read the chain implementation in src/chain/chain.ts before extending composition behaviour
  • Read src/chain/chain.test.ts before modifying chain semantics
  • If adding a new strategy subpath, create the standalone api-auth-<strategy> package first, then add a re-export barrel here
  • Keep the api-<seam>-<plugin> convention — strategies are plugins for the auth seam