npm package: @genation/sdk-server
Description: OAuth 2.1 client for Node.js server environments. Uses confidential client flow with `client_secret`.
Latest version: 0.4.2

# @genation/sdk-server

OAuth 2.1 client for Node.js server environments. Uses confidential client flow with `client_secret`.

## Installation

```bash
npm install @genation/sdk-server
```

## Requirements

- Node.js 18+
- Express.js (or compatible framework)

## Quick Start

```typescript
import { createConfidentialClient } from "@genation/sdk-server";

const client = createConfidentialClient({
    clientId: "your-client-id",
    clientSecret: "your-client-secret", // Server-side only!
    redirectUri: "http://localhost:3000/callback",
});

// Generate login URL
const { url, codeVerifier, state } = await client.signIn();
res.redirect(url);

// Handle callback
const tokens = await client.handleCallback(code, codeVerifier);
res.cookie("session", tokens.accessToken, { httpOnly: true, secure: true });

// Verify session from cookie
const session = await client.getSession(req.headers.cookie);
```

## Configuration

```typescript
createConfidentialClient({
    clientId: string;         // Required — your OAuth client ID
    clientSecret: string;     // Required — server-side only
    redirectUri: string;      // Required — callback URL
    scopes?: string[];        // Optional — default: []
    authUrl?: string;         // Optional — default: Genation Auth
    storage?: "cookie" | "memory"; // Default: "cookie"
    cookieOptions?: CookieOptions;
    ffApiUrl?: string;        // Optional — for license API
});
```

## Auth Middleware

Express middleware for protecting routes:

```typescript
import { createAuthMiddleware } from "@genation/sdk-server/middleware";

const { handler, getSession } = createAuthMiddleware({
    client,
    cookieName: "session",
});

app.use("/api/protected", handler);

app.get("/api/me", handler, async (req, res) => {
    const session = getSession(req);
    res.json(session?.user);
});
```

### Middleware Options

```typescript
createAuthMiddleware({
    client: ConfidentialClient;    // Required
    cookieName?: string;             // Default: "session"
    cookieOptions?: CookieOptions;   // Custom cookie settings
    optional?: boolean;              // Allow unauthenticated requests
    onUnauthenticated?: (req, res) => void; // Custom handler
});
```

## API Reference

### `client.signIn()`

Generates authorization URL with PKCE.

```typescript
const { url, codeVerifier, state } = await client.signIn();
res.redirect(url);
```

### `client.handleCallback(code, codeVerifier)`

Exchanges authorization code for tokens.

```typescript
const tokens = await client.handleCallback(code, codeVerifier);
```

### `client.getSession(cookieHeader)`

Verifies and returns session from cookie.

```typescript
const session = await client.getSession(req.headers.cookie);
```

### `client.signOut(cookieHeader)`

Revokes tokens and clears session.

```typescript
await client.signOut(req.headers.cookie);
```

### `client.getLicenses()`

Fetches licenses for the authenticated user.

```typescript
const licenses = await client.getLicenses(cookieHeader);
```

## Cookie Options

```typescript
interface CookieOptions {
    name?: string;       // Cookie name
    httpOnly?: boolean;   // Default: true
    secure?: boolean;     // Default: true in production
    sameSite?: "strict" | "lax" | "none";
    maxAge?: number;      // Seconds
    path?: string;        // Default: "/"
    domain?: string;
}
```

## Session Object

```typescript
interface Session {
    accessToken: string;
    refreshToken?: string;
    expiresIn: number;
    expiresAt: number;
    user: User | null;
}
```

## Security

- `client_secret` is never exposed to the browser
- Tokens stored in `httpOnly` cookies
- PKCE + state parameter for CSRF protection
- Automatic token refresh

## License

MIT