npm package: @intelicity/gates-sdk
Description: Simple SDK for authenticating users with AWS Cognito JWT tokens
Author: Gabriel Godoy
Latest version: 0.2.1

# Gates SDK

Node.js SDK for the Gates authentication system (AWS Cognito). Provides JWT token verification, group-based access control, admin user management, and framework-agnostic middleware.

## Installation

```bash
npm install @intelicity/gates-sdk
```

## Features

- JWT verification for both access and id tokens
- Admin user management (create + assign to client/group)
- Framework-agnostic middleware (works with Fastify, Express, etc.)
- Built-in JWKS caching (1h TTL)
- Group-based access control (Cognito Groups)
- Comprehensive error hierarchy

## Usage

### Token Verification

```typescript
import { AuthService } from "@intelicity/gates-sdk";

const auth = new AuthService(
  "sa-east-1",           // AWS region
  "sa-east-1_xxxxxxxxx", // User Pool ID
  "your-client-id"       // Cognito App Client ID
);

const user = await auth.verifyToken(accessToken);
// user.user_id, user.groups, user.token_use, user.email?, user.name?
```

Supports both `access_token` (validates `client_id` claim) and `id_token` (validates `aud` claim). The `token_use` field on the returned user indicates which type was verified.

### Middleware

Framework-agnostic functions for request authentication:

```typescript
import { handleAuth, AuthService } from "@intelicity/gates-sdk";

const service = new AuthService(region, userPoolId, clientId);

// Fastify
app.addHook("preHandler", async (req) => {
  req.user = await handleAuth(req.headers.authorization, {
    service,
    requiredGroups: "GAIA",
  });
});

// Express
app.use(async (req, res, next) => {
  try {
    req.user = await handleAuth(req.headers.authorization, {
      service,
      requiredGroups: "GAIA",
    });
    next();
  } catch (e) { next(e); }
});
```

Individual functions are also available:

```typescript
import { extractToken, authenticate, authorize } from "@intelicity/gates-sdk";

const token = extractToken(req.headers.authorization); // Bearer token extraction
const user = await authenticate(token, service);        // JWT verification
authorize(user, ["GAIA", "RECAPE"]);                    // Group check (throws if unauthorized)
```

### Error Handling

```typescript
import {
  TokenExpiredError,
  InvalidTokenError,
  UnauthorizedGroupError,
  GatesError,
} from "@intelicity/gates-sdk";

try {
  const user = await auth.verifyToken(token);
} catch (error) {
  if (error instanceof TokenExpiredError) {
    // error.code === "TOKEN_EXPIRED"
  } else if (error instanceof InvalidTokenError) {
    // error.code === "INVALID_TOKEN"
  } else if (error instanceof UnauthorizedGroupError) {
    // error.code === "UNAUTHORIZED_GROUP"
    // error.requiredGroups: string[]
  } else if (error instanceof GatesError) {
    // error.code, error.message
  }
}
```

### Admin Service (User Management)

For creating users and managing system access (requires admin id_token):

```typescript
import { GatesAdminService } from "@intelicity/gates-sdk";

const admin = new GatesAdminService({
  baseUrl: "https://abc123.execute-api.sa-east-1.amazonaws.com/prod",
});

// Create a new user and add to a client (group)
// Internally calls POST /create-user then PUT /update-user
const { sub } = await admin.createUser(adminIdToken, {
  email: "newuser@company.com",
  name: "New User",
  role: "CLIENT_USER",
  client: "GAIA",
});

// Later: add/remove user access to other systems
await admin.updateUser(adminIdToken, {
  user_id: sub,
  clients_to_add: ["RECAPE"],
  clients_to_remove: ["INFORMS"],
});
```

## API Reference

### `AuthService`

```typescript
new AuthService(region: string, userPoolId: string, clientId: string)
```

- `verifyToken(token: string): Promise<GatesUser>` — Verifies JWT, returns user

### `GatesAdminService`

```typescript
new GatesAdminService({ baseUrl: string })
```

- `createUser(idToken: string, params: CreateUserParams): Promise<CreateUserResponse>` — Creates user in Gates
- `updateUser(idToken: string, params: UpdateUserParams): Promise<void>` — Manages user's system access

### Types

```typescript
type GatesUser = {
  user_id: string;              // from 'sub'
  email?: string;               // only in id_tokens
  name?: string;                // only in id_tokens
  role?: string;                // from 'custom:general_role'
  groups: string[];             // from 'cognito:groups'
  token_use: "access" | "id";
  exp: number;
  iat: number;
};

type GatesRole = "INTERNAL_ADMIN" | "INTERNAL_USER" | "CLIENT_ADMIN" | "CLIENT_USER";

```

### Error Codes

| Code                       | Class                       | Description                     |
| -------------------------- | --------------------------- | ------------------------------- |
| `TOKEN_EXPIRED`            | `TokenExpiredError`         | JWT has expired                 |
| `INVALID_TOKEN`            | `InvalidTokenError`         | Invalid or malformed token      |
| `MISSING_AUTHORIZATION`    | `MissingAuthorizationError` | Authorization header missing    |
| `UNAUTHORIZED_GROUP`       | `UnauthorizedGroupError`    | User not in required group      |
| `API_REQUEST_ERROR`        | `ApiRequestError`           | Gates API request failed        |
| `MISSING_PARAMETER`        | `MissingParameterError`     | Required parameter missing      |
| `INVALID_PARAMETER`        | `InvalidParameterError`     | Parameter has invalid value     |

## Development

```bash
npm install
npm run build       # tsc && tsc-alias → dist/
npm run typecheck   # tsc --noEmit
npm test            # vitest run
npm run test:watch  # vitest (watch mode)
```

## License

MIT