Project Integration
This guide shows how to integrate Kyqu authentication into your product.
Setup
Each project in Kyqu has:
- A Project ID (UUID)
- A Public Key (
pk_...) — identifies the project - A Secret Key (
sk_...) — shown once, stored as hash
Store the project ID and public key in your application's configuration:
const KYQU_CONFIG = {
baseUrl: "https://api.kyqu.dev", // Kyqu API host
projectId: "a1b2c3d4-...",
publicKey: "pk_abc123..."
};
`baseUrl` must point to where the Kyqu **API** is served.
## Using the Client SDK
The `@kyqu/client` package is the recommended way to integrate:
```bash
npm install @kyqu/client
import { KyquClient } from "@kyqu/client";
const kyqu = new KyquClient({
baseUrl: "https://api.kyqu.dev",
projectId: "your-project-id",
publicKey: "pk_your-public-key"
});
Direct API Usage (Vanilla JS)
class KyquAuth {
constructor(baseUrl, projectId, publicKey) {
this.baseUrl = baseUrl;
this.projectId = projectId;
this.publicKey = publicKey;
this.authBase = `${baseUrl}/api/projects/${projectId}/auth`;
}
async request(path, options = {}) {
const headers = {
"Content-Type": "application/json",
"x-kyqu-public-key": this.publicKey,
...options.headers
};
const res = await fetch(`${this.authBase}/${path}`, {
method: options.method || "GET",
headers,
body: options.body ? JSON.stringify(options.body) : undefined
});
const data = await res.json();
if (!res.ok) throw new Error(data.error || "Request failed");
return data;
}
signup(email, password, name) {
return this.request("signup", {
method: "POST",
body: { email, password, name }
});
}
login(email, password) {
return this.request("login", {
method: "POST",
body: { email, password }
});
}
getUser(token) {
return this.request("me", {
headers: { Authorization: `Bearer ${token}` }
});
}
}
Auth Flows
Email/Password Signup
try {
const { user, session, verificationRequired } = await kyqu.signup({
email: "user@example.com",
password: "correct-horse-battery-staple",
name: "User Name"
});
if (verificationRequired) {
// Show "Check your email" message
// User must verify before they can log in
} else {
// User is automatically logged in
localStorage.setItem("session", session.token);
}
} catch (err) {
// Handle error (validation, duplicate email, etc.)
}
Email/Password Login
try {
const { user, session } = await kyqu.login({
email: "user@example.com",
password: "correct-horse-battery-staple"
});
localStorage.setItem("session", session.token);
} catch (err) {
if (err.message === "TOTP_REQUIRED") {
// Prompt user for 2FA code
showTotpPrompt();
} else {
showError(err.message);
}
}
Login with TOTP 2FA
// First call returns TOTP_REQUIRED
// Then retry with TOTP code:
const { user, session } = await kyqu.login({
email: "user@example.com",
password: "correct-horse-battery-staple",
totpCode: "123456"
});
// Or use a backup code:
const { user, session } = await kyqu.login({
email: "user@example.com",
password: "correct-horse-battery-staple",
backupCode: "abcd-efgh-ijkl-mnop"
});
Session Management
// Check current user
const token = localStorage.getItem("session");
if (token) {
try {
const user = await kyqu.getUser(token);
// User is authenticated
} catch {
// Token expired or revoked
localStorage.removeItem("session");
redirectToLogin();
}
}
// Logout
await kyqu.logout(token);
localStorage.removeItem("session");
// List active sessions
const sessions = await kyqu.listSessions(token);
// Revoke a specific session (e.g., "log out other devices")
await kyqu.revokeSession(token, sessionId);
Email Verification
// Request verification email
await kyqu.requestEmailVerification("user@example.com");
// Confirm verification (from link click)
// GET /api/projects/{id}/auth/verify-email/confirm?token=...
// Or via API:
const { user } = await kyqu.confirmEmailVerification(token);
Password Reset
// Request reset email
await kyqu.requestPasswordReset("user@example.com");
// Confirm reset
const { user, session } = await kyqu.confirmPasswordReset({
token: "reset-token-from-email",
password: "new-password-42"
});
Magic Link
// Request magic link email
await kyqu.requestMagicLink("user@example.com");
// Option A: API confirm (POST) — returns session directly
const { user, session } = await kyqu.confirmMagicLink(tokenFromEmail);
// Option B: Browser email link (GET) — user lands on your login_url with session_code
// On your login page:
const params = new URLSearchParams(window.location.search);
const sessionCode = params.get("session_code");
if (sessionCode) {
const { user, session } = await kyqu.exchangeSessionCode(sessionCode);
localStorage.setItem("session", session.token);
// Clean up URL: remove session_code from address bar
}
Configure loginUrl in project auth settings to your app login page.
Password change
const token = localStorage.getItem("session");
await kyqu.changePassword(token, {
currentPassword: "old-password",
newPassword: "new-secure-password"
});
TOTP Enrollment
// Step 1: Start enrollment
const { enrollmentUrl } = await kyqu.enrollTotp(token);
// Show QR code to user (render enrollmentUrl as QR)
// Step 2: Confirm with code from authenticator app
const { backupCodes } = await kyqu.confirmTotp(token, "123456");
// Display backup codes to user — they're shown once!
Passkey Authentication
// Registration
const options = await kyqu.getPasskeyRegistrationOptions(token);
const credential = await navigator.credentials.create({ publicKey: options });
await kyqu.registerPasskey(token, credential, "My MacBook");
// Authentication
const authOptions = await kyqu.getPasskeyAuthenticationOptions();
const assertion = await navigator.credentials.get({ publicKey: authOptions });
const { user, session } = await kyqu.authenticateWithPasskey(assertion);
OAuth Social Login
// Redirect to Google
window.location.href = kyqu.getOAuthAuthorizeUrl("google");
// Kyqu handles the callback; user lands back with a session
ID Token (OIDC)
const { idToken } = await kyqu.getIdToken(token);
// RS256-signed JWT with sub, email, name, iss, aud, iat, exp
Auto-Refresh Session
const managed = kyqu.withAutoRefresh(session, {
storage: localStorage,
marginSeconds: 60,
onRefresh: (newSession) => console.log("Token refreshed"),
onError: () => redirectToLogin()
});
// Always returns a fresh token
fetch("/api/data", {
headers: { Authorization: `Bearer ${managed.getToken()}` }
});
React Integration
import { KyquProvider, useKyqu, useKyquUser } from "@kyqu/client/react";
function App() {
return (
<KyquProvider client={kyqu} storage={localStorage}>
<Main />
</KyquProvider>
);
}
function Main() {
const { user, loading, login, logout } = useKyqu();
if (loading) return <div>Loading...</div>;
if (!user) return <LoginPage onLogin={login} />;
return <Dashboard user={user} onLogout={logout} />;
}
Best Practices
- Store session tokens securely — Use
HttpOnlycookies if possible, or secure client-side storage - Handle 401 responses — Redirect to login when token is invalid/expired
- Use auto-refresh — Wrap sessions with
withAutoRefresh()instead of re-authenticating - Use HTTPS — Never send tokens over plain HTTP
- Validate on page load — React hook
useKyqu()handles session restore automatically - Monitor webhooks — Listen for auth events to sync user status