Structured integration guide for AI coding assistants (Claude Code, GitHub Copilot, Cursor, etc.)
Copy the content below into your AI assistant's context window, or fetch the raw version from /docs/ai-instructions/raw in your CI or script.
# TAJMAC Auth — AI Integration Guide
## What is TAJMAC Auth?
TAJMAC Auth is a self-hosted identity platform providing complete authentication infrastructure.
- REST API server on port 3002 (Hono / Bun)
- Admin portal on port 3003 (Next.js)
- Hosted login UI on port 3004 (Next.js)
- Database: PostgreSQL with schema `tajmac_auth`
## npm / package
There is no published SDK yet. Integrate by calling the REST API directly.
## Key API endpoints
### Authentication (public — no auth required)
```
POST /api/v1/auth/sign-in/email
Body: { email, password, appSlug }
Response: sets tajmac.session HttpOnly cookie
POST /api/v1/auth/sign-up/email
Body: { email, password, name, appSlug }
Response: sets tajmac.session HttpOnly cookie
GET /api/v1/auth/session
Cookie: tajmac.session=<token>
Response: { user: { id, email, name, emailVerified }, session: { id, expiresAt } }
POST /api/v1/auth/sign-out
Cookie: tajmac.session=<token>
Response: 200, clears cookie
POST /api/v1/auth/magic-link/send
Body: { email, appSlug }
Response: { ok: true }
GET /api/v1/auth/magic-link/verify?token=<token>
Response: sets tajmac.session cookie, redirects
POST /api/v1/auth/forgot-password
Body: { email, appSlug }
Response: { ok: true }
POST /api/v1/auth/reset-password
Body: { token, password }
Response: { ok: true }
```
### Portal management (requires tajmac.session cookie — portal admin only)
```
GET /api/v1/portal/apps
POST /api/v1/portal/apps
GET /api/v1/portal/apps/:slug
PATCH /api/v1/portal/apps/:slug
DELETE /api/v1/portal/apps/:slug
GET /api/v1/portal/admin/users
GET /api/v1/portal/admin/stats
GET /api/v1/portal/organizations
POST /api/v1/portal/organizations
GET /api/v1/portal/organizations/:id
PATCH /api/v1/portal/organizations/:id
DELETE /api/v1/portal/organizations/:id
GET /api/v1/portal/permissions/roles
POST /api/v1/portal/permissions/roles
POST /api/v1/portal/permissions/check
GET /api/v1/portal/admin/flags
POST /api/v1/portal/admin/flags
GET /api/v1/portal/admin/api-keys
POST /api/v1/portal/admin/api-keys
DELETE /api/v1/portal/admin/api-keys/:id
GET /api/v1/portal/oauth-clients
POST /api/v1/portal/oauth-clients
```
### OIDC Provider
```
GET /.well-known/openid-configuration
GET /.well-known/jwks.json
GET /oidc/auth (authorization endpoint)
POST /oidc/token (token endpoint)
GET /oidc/me (userinfo endpoint)
```
## Session validation
```typescript
// In Next.js middleware or API route (server-side)
const sessionToken = req.cookies.get("tajmac.session")?.value;
if (!sessionToken) return; // not authenticated
const res = await fetch(`${process.env.TAJMAC_AUTH_URL}/api/v1/auth/session`, {
headers: { Cookie: `tajmac.session=${sessionToken}` },
});
if (!res.ok) return; // invalid or expired session
const { user, session } = await res.json();
// user.id, user.email, user.name
```
## Sign-in (server-side proxy pattern)
```typescript
// Next.js API route: app/api/auth/sign-in/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function POST(req: NextRequest) {
const body = await req.json();
const upstream = await fetch(
`${process.env.TAJMAC_AUTH_URL}/api/v1/auth/sign-in/email`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ ...body, appSlug: process.env.TAJMAC_APP_SLUG }),
},
);
const json = await upstream.json();
const res = NextResponse.json(json, { status: upstream.status });
// Forward Set-Cookie so session cookie lands on your domain
upstream.headers.forEach((value, key) => {
if (key.toLowerCase() === "set-cookie") {
res.headers.append("Set-Cookie", value);
}
});
return res;
}
```
## Environment variables required
```bash
# Your app's .env.local
TAJMAC_AUTH_URL=http://localhost:3002 # auth server URL
TAJMAC_APP_SLUG=my-app # slug of your registered app
# Optional: internal URL (faster in same network)
TAJMAC_AUTH_INTERNAL_URL=http://auth-server:3002
```
## Common patterns
### Next.js middleware (protect all dashboard routes)
```typescript
// middleware.ts
import { NextRequest, NextResponse } from "next/server";
export async function middleware(req: NextRequest) {
const session = req.cookies.get("tajmac.session")?.value;
if (!session) {
return NextResponse.redirect(new URL("/login", req.url));
}
// Optional: validate session on every request (adds latency)
// const res = await fetch(...)
return NextResponse.next();
}
export const config = {
matcher: ["/dashboard/:path*", "/profile/:path*"],
};
```
### React hook (client component)
```typescript
"use client";
import { useState, useEffect } from "react";
export function useSession() {
const [session, setSession] = useState<{ user: { id: string; email: string; name: string } } | null>(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("/api/auth/session")
.then(r => r.ok ? r.json() : null)
.then(setSession)
.catch(() => setSession(null))
.finally(() => setLoading(false));
}, []);
return { session, loading };
}
```
### Express.js middleware
```typescript
import type { Request, Response, NextFunction } from "express";
export async function requireAuth(req: Request, res: Response, next: NextFunction) {
const session = req.cookies["tajmac.session"];
if (!session) return res.status(401).json({ error: "Unauthorized" });
const r = await fetch(`${process.env.TAJMAC_AUTH_URL}/api/v1/auth/session`, {
headers: { Cookie: `tajmac.session=${session}` },
}).catch(() => null);
if (!r?.ok) return res.status(401).json({ error: "Invalid session" });
const data = await r.json();
(req as Request & { user: unknown }).user = data.user;
next();
}
```
## Important notes
1. The session cookie is HttpOnly — you cannot read it in JavaScript. Always use server-side session validation.
2. Each app has a unique `appSlug`. Sign-in requests MUST include the correct `appSlug` for the app.
3. The portal app slug is "portal" — never sign in to the portal app from your application.
4. API calls to `/api/v1/portal/*` require a portal admin session. Use API keys for programmatic access.
5. TAJMAC Auth does NOT use JWTs for sessions — it uses 256-bit random tokens stored in the database.