← Files InsForgeARCHIVED FILE
skills/insforge-integrations/references/kinde.md
4.69 KB · Oct 5, 2026 · 18:29 UTC
# InsForge + Kinde Integration Guide
Kinde **does not support custom JWT signing keys**, so you sign a separate JWT server-side using `jsonwebtoken`. The flow: get the Kinde user from the server session → sign a JWT with InsForge's secret → pass it to InsForge as `accessToken` (deprecated alias: `edgeFunctionToken`).
## Key packages
- `@kinde-oss/kinde-auth-nextjs` — Kinde SDK for Next.js
- `@insforge/sdk` — InsForge client
- `jsonwebtoken` + `@types/jsonwebtoken` — for server-side JWT signing
## Recommended Workflow
```text
1. Create Kinde application → Kinde Dashboard (manual)
2. Create/link InsForge project → npx @insforge/cli create or link
3. Install deps + configure env → npm install, .env.local
4. Create Kinde auth route → app/api/auth/[kindeAuth]/route.js
5. Create InsForge client utility → lib/insforge.ts (server-side JWT signing)
6. Set up InsForge database → requesting_user_id() + table + RLS
7. Build features → CRUD pages using InsForge client
```
## Dashboard setup (manual, cannot be automated)
### Kinde Application
- Create in Kinde Dashboard > Add application
- Type: **Back-end web**, SDK: **Next.js**
- Set **Allowed callback URL** to `http://localhost:3000/api/auth/kinde_callback`
- Set **Allowed logout redirect URL** to `http://localhost:3000`
- Enable desired auth methods (Email, Google, etc.) under Authentication
- Note down **Domain**, **Client ID**, **Client Secret** from App Keys
### InsForge Project
- Create via `npx @insforge/cli create` or link via `npx @insforge/cli link --project-id <id>`
- Get the JWT secret via CLI: `npx @insforge/cli secrets get JWT_SECRET`
- Note down **URL** and **Anon Key** from InsForge, then export the CLI value as `INSFORGE_JWT_SECRET`
## Kinde auth route
- Create `app/api/auth/[kindeAuth]/route.js` that exports `handleAuth()` from `@kinde-oss/kinde-auth-nextjs/server`
```javascript
// app/api/auth/[kindeAuth]/route.js
import { handleAuth } from "@kinde-oss/kinde-auth-nextjs/server";
export const GET = handleAuth();
```
## InsForge client
- Create a server-side utility at `lib/insforge.ts` — cannot be used in client components
- Use `getKindeServerSession()` to get `getUser`
- Sign a JWT with `jsonwebtoken` using `process.env.INSFORGE_JWT_SECRET`
- Required claims: `sub` (from `user.id`), `role: "authenticated"`, `aud: "insforge-api"`, `email`
- Set `expiresIn: '1h'`
- Pass the signed token as `accessToken` to `createClient`
```typescript
// lib/insforge.ts
import { createClient } from '@insforge/sdk';
import { getKindeServerSession } from '@kinde-oss/kinde-auth-nextjs/server';
import jwt from 'jsonwebtoken';
export async function createInsForgeClient() {
const { getUser } = getKindeServerSession();
const user = await getUser();
let accessToken: string | undefined;
if (user) {
accessToken = jwt.sign(
{
sub: user.id,
role: 'authenticated',
aud: 'insforge-api',
email: user.email,
},
process.env.INSFORGE_JWT_SECRET!,
{ expiresIn: '1h' }
);
}
return createClient({
baseUrl: process.env.NEXT_PUBLIC_INSFORGE_URL!,
accessToken,
});
}
```
## Database setup
- Kinde user IDs are strings (e.g. `kp_1234abcd`), not UUIDs — use `TEXT` columns for `user_id`
- Create a `requesting_user_id()` SQL function that extracts the `sub` claim from `auth.jwt()` as text
- Set `user_id` column default to `requesting_user_id()` so it auto-populates on insert
- Enable RLS and create policies that compare `user_id = requesting_user_id()`
```sql
create or replace function public.requesting_user_id()
returns text
language sql stable
as $$
select nullif(auth.jwt() ->> 'sub', '')::text
$$;
```
## Environment variables
| Variable | Source |
|----------|--------|
| `KINDE_CLIENT_ID` | Kinde Dashboard > App Keys |
| `KINDE_CLIENT_SECRET` | Kinde Dashboard > App Keys |
| `KINDE_ISSUER_URL` | `https://YOUR_DOMAIN.kinde.com` |
| `KINDE_SITE_URL` | `http://localhost:3000` |
| `KINDE_POST_LOGOUT_REDIRECT_URL` | `http://localhost:3000` |
| `KINDE_POST_LOGIN_REDIRECT_URL` | `http://localhost:3000` |
| `NEXT_PUBLIC_INSFORGE_URL` | InsForge Dashboard |
| `NEXT_PUBLIC_INSFORGE_ANON_KEY` | InsForge Dashboard |
| `INSFORGE_JWT_SECRET` | InsForge CLI (`npx @insforge/cli secrets get JWT_SECRET`) |
## Common Mistakes
| Mistake | Solution |
|---------|----------|
| ❌ Using Kinde's JWT directly with InsForge | ✅ Kinde doesn't sign with your secret — sign a separate JWT server-side |
| ❌ Using InsForge client in a client component | ✅ `getKindeServerSession` is server-only — keep the utility server-side |
| ❌ Using `auth.uid()` for RLS policies | ✅ Use `requesting_user_id()` — Kinde IDs are strings, not UUIDs |
SHA-256: db0e8b90ff229e1e721b3ccc28d7a4229beb84331bd6adfb0825d481e424dc75