Getting Started
Register an app, wire the SDK, ship.
Getting Started
End-to-end walkthrough — from “I have a SvelteKit/Next.js/Laravel app” to “users are logging in via WolfieAuth”. Total wall-clock time: 5–10 minutes if you copy-paste, longer if you stop to read.
1. Register your app at the WolfieAuth admin
Go to auth.wolfieguard.com/admin/clients/new and fill in:
| Field | What to put |
|---|---|
| Name | Human-readable, e.g. “Acme CRM” |
| App slug | Lowercase short name, e.g. crm — gets auto-prefixed to <yourOrgSlug>-crm so two orgs can both have a “crm” without collision |
| Redirect URIs | Where WolfieAuth sends users back after login. SvelteKit/React: https://your-app.com/auth/callback. Next.js Auth.js: https://your-app.com/api/auth/callback/wolfieauth. WordPress: https://your-site.com/wp-admin/admin-ajax.php?action=wolfieauth_callback. Perfex: https://your-perfex.com/wolfieauth_client/callback |
| Trusted | Enable for your own apps so the consent screen is skipped on every login. Leave OFF for third-party apps |
| Owner org | Defaults to your active org — the org whose Stripe Connect account receives plan revenue |
You’ll get back a clientId and a clientSecret (shown ONCE — store immediately). Add them to your app’s env:
WOLFIEAUTH_ISSUER=https://auth.wolfieguard.com
WOLFIEAUTH_CLIENT_ID=youorgslug-crm
WOLFIEAUTH_CLIENT_SECRET=<from-admin-panel>
2. Pick a SaaS RBAC template
Most apps fit one of five canonical shapes. Apply one in /admin/clients/<id>#users → Roles → 📋 Use template:
| Template | Roles | Best for |
|---|---|---|
| Solo | Owner | Personal tools, founder-only |
| B2B Team | Admin / Editor / Viewer | CRM, project mgmt |
| B2B Hierarchical | Admin / Billing-Admin / Editor / Auditor / Viewer | Accounting, ERP |
| Marketplace | Vendor-Admin / Vendor-Staff / Customer | Multi-vendor stores |
| Internal Tool | Super-Admin / Tenant-Admin / Member / Auditor | Platform-owner + sub-tenants |
Each role’s permissions[] uses canonical strings like members.invite / billing.read / plans.write. Your downstream app reads them from claims.wolfieauth_permissions[]. Mix and match — apply the template, then add a custom role for your specific niche need.
3. Drop in the SDK
Pick the matching SDK from the SDKs page. For a SvelteKit example:
$ npm install @wolfieauth/sdk-sveltekit
// src/hooks.server.ts
import { sequence } from '@sveltejs/kit/hooks';
import { createWolfieAuthHandle, pendingApprovalGate } from '@wolfieauth/sdk-sveltekit/server';
const auth = createWolfieAuthHandle({
template: {
id: 'guest-request',
issuer: process.env.WOLFIEAUTH_ISSUER!,
clientId: process.env.WOLFIEAUTH_CLIENT_ID!,
branding: { appName: 'Acme CRM' },
},
sessionSecret: process.env.SESSION_SECRET!,
});
export const handle = sequence(auth, pendingApprovalGate);
<!-- src/routes/auth/login/+page.svelte -->
<script>
import { LoginPage } from '@wolfieauth/sdk-sveltekit/components';
export let data;
</script>
<LoginPage config={data.loginConfig} />
That’s it for SvelteKit. Same shape for Next.js, Express, Django, Laravel — see the SDKs page for each.
4. Mirror the user into your app DB
Every app needs local Organization + OrgMembership rows so its own queries can FK to org-id. Mirror happens on first OIDC callback per (user × org) in the SDK middleware:
const mirror: Handle = async ({ event, resolve }) => {
const c = event.locals.session?.claims;
if (!c) return resolve(event);
const org = await prisma.organization.upsert({
where: { wolfieauthOrgId: c.wolfieauth_org_id },
create: {
name: c.wolfieauth_org_name,
type: c.wolfieauth_org_tier === 'PLATFORM' ? 'SUPER' : 'CLIENT',
wolfieauthOrgId: c.wolfieauth_org_id,
wolfieauthSlug: c.wolfieauth_org_slug,
},
update: { name: c.wolfieauth_org_name },
});
await prisma.orgMembership.upsert({
where: { userId_organizationId: { userId: c.sub, organizationId: org.id } },
create: { userId: c.sub, organizationId: org.id, role: mapRole(c.wolfieauth_role_slug) },
update: { role: mapRole(c.wolfieauth_role_slug) },
});
event.locals.org = org;
return resolve(event);
};
Critical invariant: No local User table. WolfieAuth IS your user table. Store userId = sub everywhere; refresh user details (name, email, avatar) from /userinfo when you need them, cache in-process for ~5 minutes. This eliminates an entire class of stale-record bugs.
5. Your app reads claims to gate features
import { hasActiveFeature, isApproved } from '@wolfieauth/sdk-core/oidc/claims';
if (!isApproved(claims)) return redirect('/auth/pending');
if (hasActiveFeature(claims, 'youorgslug-crm', 'ksef_enabled')) {
// user has the KSeF feature on their active org's subscription
}
The wolfieauth_features[] claim is a flat ["<appClientId>:<feature>", …] array — hasFeature() looks across every active subscription on every org the user belongs to (union mode), hasActiveFeature() filters to the user’s currently-selected org (workspace mode). Pick whichever model fits your app.
What’s next
- SSO & Sessions to understand what’s actually happening on each request
- Plans & Billing to start charging
- Admin for Users tab, Comp overrides, Theme, MCP tokens
Last updated: