npm package: @kid-oauth/sdk
Description: Official SDK for KID OAuth2 - JavaScript and TypeScript helper library. Built with love by KOOMPI Team.
Author: KOOMPI Team
Latest version: 2.1.1

# @kid-oauth/sdk

Official SDK for integrating with KID Identity Provider. Handles OAuth2 authorization, PKCE, token exchange, wallet operations, and provides React components for quick setup.

```bash
npm install @kid-oauth/sdk
```

## Table of Contents

- [Quick Start (React)](#quick-start-react)
- [Quick Start (Vanilla JS / Server)](#quick-start-vanilla-js--server)
- [Authentication](#authentication)
  - [React Provider](#react-provider)
  - [Token Exchange (Server-Side)](#token-exchange-server-side)
  - [Pre-built Handlers](#pre-built-handlers)
- [Wallet](#wallet)
  - [Get Wallet Info](#get-wallet-info)
  - [Sign Messages](#sign-messages)
  - [Send Transactions](#send-transactions)
  - [Contract Registry](#contract-registry)
- [API Reference](#api-reference)

---

## Quick Start (React)

The fastest way to add KID auth to a React / Next.js app.

### 1. Wrap your app with `KIDProvider`

```tsx
// app/layout.tsx (or _app.tsx)
import { KIDProvider } from '@kid-oauth/sdk';

export default function Layout({ children }) {
  return (
    <KIDProvider
      clientId="your_client_id"
      redirectUri="http://localhost:3000"
      tokenEndpoint="/api/auth/callback"
      refreshEndpoint="/api/auth/refresh"
    >
      {children}
    </KIDProvider>
  );
}
```

### 2. Create the server-side token endpoint

```ts
// app/api/auth/callback/route.ts
import { createTokenHandler } from '@kid-oauth/sdk/server';

const handler = createTokenHandler({
  clientId: process.env.KID_CLIENT_ID!,
  clientSecret: process.env.KID_CLIENT_SECRET!,
  redirectUri: process.env.KID_REDIRECT_URI!,
});

export async function POST(req: Request) {
  return handler(req);
}
```

### 3. Use the hooks and components

```tsx
import { useAuth, useUser, SignInButton, SignOutButton, SignedIn, SignedOut } from '@kid-oauth/sdk';

export default function Page() {
  return (
    <div>
      <SignedOut>
        <SignInButton>Log in with KID</SignInButton>
      </SignedOut>

      <SignedIn>
        <Profile />
        <SignOutButton />
      </SignedIn>
    </div>
  );
}

function Profile() {
  const { user } = useUser();
  return <p>Welcome, {user?.fullname || user?.email}</p>;
}
```

That's it. The provider handles PKCE, state, token storage, refresh, and user fetching automatically.

---

## Quick Start (Vanilla JS / Server)

For non-React apps or full server-side control.

### Browser: Redirect to login

```ts
import { KIDOAuthClient } from '@kid-oauth/sdk';

const client = new KIDOAuthClient({
  clientId: 'your_client_id',
  redirectUri: 'http://localhost:3000/callback',
});

// Generates PKCE + state automatically
const loginUrl = await client.getLoginUrl({ scope: 'openid profile email' });
window.location.href = loginUrl;
```

### Server: Exchange code for tokens

```ts
import { KIDOAuthServer } from '@kid-oauth/sdk/server';

const server = new KIDOAuthServer({
  clientId: process.env.KID_CLIENT_ID!,
  clientSecret: process.env.KID_CLIENT_SECRET!,
  redirectUri: process.env.KID_REDIRECT_URI!,
});

// Exchange the authorization code
const tokens = await server.exchangeCode({ code, codeVerifier });

// Get user info
const user = await server.getUserInfo(tokens.access_token);

// Refresh tokens
const newTokens = await server.refreshToken({
  refreshToken: tokens.refresh_token,
});
```

### Combined (KIDAuth)

`KIDAuth` combines both client and server in one class:

```ts
import { KIDAuth } from '@kid-oauth/sdk';

const auth = new KIDAuth({
  clientId: 'your_client_id',
  clientSecret: 'your_client_secret',
  redirectUri: 'http://localhost:3000/callback',
});

// Build login URL (browser)
const url = await auth.createLoginUrl();

// Handle callback (server)
const tokens = await auth.handleCallback();
const user = await auth.getUserInfo(tokens.access_token);
```

---

## Authentication

### React Provider

`KIDProvider` manages the full OAuth lifecycle in React apps.

```tsx
<KIDProvider
  clientId="your_client_id"       // Required
  redirectUri="http://localhost:3000"  // Required
  tokenEndpoint="/api/auth/callback"  // Your server route for code exchange
  refreshEndpoint="/api/auth/refresh" // Your server route for token refresh
  userinfoEndpoint="/api/auth/user"   // Optional: custom userinfo endpoint
  baseUrl="https://api.kid.koompi.org/oauth" // Optional: defaults to this
>
  {children}
</KIDProvider>
```

**Hooks:**

| Hook | Returns |
|------|---------|
| `useAuth()` | `{ user, isLoaded, isSignedIn, isLoading, error, signIn, signOut, getToken }` |
| `useUser()` | `{ user, isLoaded, isSignedIn }` |

**Components:**

| Component | Description |
|-----------|-------------|
| `<SignInButton>` | Triggers `signIn()` on click |
| `<SignOutButton>` | Triggers `signOut()` on click |
| `<SignedIn>` | Renders children only when authenticated |
| `<SignedOut>` | Renders children only when not authenticated |
| `<UserButton>` | Displays user avatar and name |

### Token Exchange (Server-Side)

After the user is redirected back with a `code`, exchange it for tokens on your server:

```ts
import { KIDOAuthServer } from '@kid-oauth/sdk/server';

const server = new KIDOAuthServer({
  clientId: process.env.KID_CLIENT_ID!,
  clientSecret: process.env.KID_CLIENT_SECRET!,
  redirectUri: process.env.KID_REDIRECT_URI!,
});

const tokens = await server.exchangeCode({
  code: 'authorization_code_from_callback',
  codeVerifier: 'pkce_verifier_from_session',
});
// tokens: { access_token, refresh_token, expires_in, token_type }
```

### Pre-built Handlers

Drop-in request handlers for Next.js App Router or any framework using the Web `Request`/`Response` API:

```ts
// app/api/auth/callback/route.ts
import { createTokenHandler } from '@kid-oauth/sdk/server';

const handler = createTokenHandler({
  clientId: process.env.KID_CLIENT_ID!,
  clientSecret: process.env.KID_CLIENT_SECRET!,
  redirectUri: process.env.KID_REDIRECT_URI!,
});

export const POST = (req: Request) => handler(req);
```

```ts
// app/api/auth/refresh/route.ts
import { createRefreshHandler } from '@kid-oauth/sdk/server';

const handler = createRefreshHandler({
  clientId: process.env.KID_CLIENT_ID!,
  clientSecret: process.env.KID_CLIENT_SECRET!,
  redirectUri: process.env.KID_REDIRECT_URI!,
});

export const POST = (req: Request) => handler(req);
```

---

## Wallet

Every KID user gets a blockchain wallet automatically. Use `KIDWalletClient` to interact with it.

```ts
import { KIDWalletClient } from '@kid-oauth/sdk';

const wallet = new KIDWalletClient({
  accessToken: 'user_access_token',
});
```

### Get Wallet Info

```ts
const info = await wallet.getWalletInfo();
// { status: 'SUCCESS', wallet: { address, public_key, network, chain_id } }
```

### Sign Messages

```ts
const result = await wallet.signMessage({
  message: 'Hello World',
  message_format: 'text', // or 'hex'
});
// { status: 'SUCCESS', signature, message_hash, signer }
```

### Send Transactions

Two ways to send transactions:

**Option 1: Raw transaction data**

```ts
const result = await wallet.sendTransaction({
  transaction: {
    to: '0xRecipientAddress',
    value: '1000000000000000000', // 1 ETH in wei
    data: '0x',                   // Optional calldata
  },
  gas_sponsorship: { enabled: true }, // Project pays gas
});
// { status: 'SUCCESS', transaction_hash, from, gas_sponsored }
```

**Option 2: Contract registry** (recommended for contract interactions)

Register your contracts in the KID dashboard first, then call them by name:

```ts
const result = await wallet.sendTransaction({
  contract_call: {
    contract: 'usdt-token',     // Registered contract name
    method: 'transfer',          // Function name
    params: ['0xRecipient', '1000000'], // Function args
  },
  gas_sponsorship: { enabled: true },
});
```

### Contract Registry

Register smart contracts in the KID dashboard under your project settings. The backend stores the ABI and handles encoding with ethers.js, so your client code stays simple.

Benefits over raw transactions:
- No client-side ABI encoding needed
- Backend validates parameters against the ABI
- Supports any contract function, not just standard ERC operations
- Max 20 contracts per project

---

## API Reference

### Imports

```ts
// Browser + React
import {
  KIDAuth,
  KIDOAuthClient,
  KIDWalletClient,
  KIDProvider,
  useAuth,
  useUser,
  SignInButton,
  SignOutButton,
  SignedIn,
  SignedOut,
  UserButton,
} from '@kid-oauth/sdk';

// Server only (no React dependency)
import {
  KIDOAuthServer,
  createTokenHandler,
  createRefreshHandler,
} from '@kid-oauth/sdk/server';
```

### Configuration

```ts
interface KIDOAuthConfig {
  clientId: string;        // Your project's client ID
  clientSecret?: string;   // Required for server-side operations
  redirectUri: string;     // OAuth callback URL
  baseUrl?: string;        // Default: "https://api.kid.koompi.org/oauth"
  defaultScope?: string | string[];
}
```

### Error Handling

All SDK errors extend `KIDError`:

```ts
import { KIDAuthError, KIDNetworkError, isKIDError } from '@kid-oauth/sdk';

try {
  const tokens = await server.exchangeCode({ code });
} catch (err) {
  if (isKIDError(err)) {
    console.log(err.code);    // e.g. 'invalid_grant'
    console.log(err.message); // e.g. 'Authorization code expired'
  }
}
```

| Error Class | When |
|-------------|------|
| `KIDAuthError` | Invalid credentials, expired codes, bad requests |
| `KIDNetworkError` | Failed to reach the KID API |
| `KIDTokenExpiredError` | Access token has expired |
| `KIDStateError` | OAuth state mismatch (CSRF protection) |

---

## Environment Variables

```env
# Public (safe for browser)
NEXT_PUBLIC_KID_CLIENT_ID=your_client_id
NEXT_PUBLIC_KID_REDIRECT_URI=http://localhost:3000

# Secret (server only)
KID_CLIENT_ID=your_client_id
KID_CLIENT_SECRET=your_client_secret
KID_REDIRECT_URI=http://localhost:3000
```

## Scripts

```bash
npm run build      # Build ESM + CJS + types
npm run typecheck  # TypeScript check
npm run lint       # ESLint
```

## License

MIT