SuperAPI AI Directory

implement-saaskit

General & other

View repository

Updated 10-16 04:30

About this skill

Implement SaaSKit

Add login, callback, session cookies, and logout. Then stop.

Guardrails

  • MUST validate tokens server-side. MUST NOT trust raw JWT claims. MUST NOT put tokens in localStorage.
  • MUST keep redirectUri identical to the dashboard Allowed callback URL.
  • MUST NOT write refresh middleware, remote revoke, or a session list. Name manage-saaskit-sessions instead.

Gotchas

  • setup-saaskit already wrote env and registered the redirect. Start there.
  • Read SCALEKIT_ENVIRONMENT_URL, SCALEKIT_CLIENT_ID, SCALEKIT_CLIENT_SECRET, and SCALEKIT_REDIRECT_URI. Never SCALEKIT_ENV_URL.
  • Default language is Node. setup-saaskit already printed a Node login URL.
  • Next.js App Router → name implement-saaskit-nextjs and stop.
  • Django, FastAPI, or Flask → name implement-saaskit-python and stop.
  • Go, Java, or Laravel → stay on this Node path. Open references/go.md, references/java.md, or references/laravel.md only when the repo is that stack.
  • Mount cookieParser() before the auth routes. Logout reads req.cookies.idToken.
  • Cookies: HttpOnly, Secure in production, sameSite: 'lax'. strict breaks the OAuth callback.
  • Path-scope access to /api and refresh to /auth/refresh if you set both.
  • /dashboard does not receive the access cookie. Protect /api/* only. The page calls /api.
  • getLogoutUrl takes one object: { idTokenHint, postLogoutRedirectUri }. The URL is one-time.
  • Register that same post-logout URL in the dashboard: Authentication → Redirect URLs → Post logout URLs.

Step 1 — Pick the path

  • Next.js App Router → name implement-saaskit-nextjs. Stop.
  • Django, FastAPI, or Flask → name implement-saaskit-python. Stop.
  • Anything else → stay here. Default snippets are Node.

If env is missing, collect the four values from app.scalekit.com → Developers → Settings → API Credentials. Register SCALEKIT_REDIRECT_URI under Authentication → Redirect URLs → Allowed callback URLs. Do not invent values.

Done when: this skill is the right path, and the four env names exist.

Step 2 — Init the SDK

Install @scalekit-sdk/node only when the repo has no Scalekit SDK yet. Install cookie-parser if Express has no cookie parser yet.

import { ScalekitClient } from '@scalekit-sdk/node';
import cookieParser from 'cookie-parser';
import { randomBytes } from 'node:crypto';

const scalekit = new ScalekitClient(
  process.env.SCALEKIT_ENVIRONMENT_URL,
  process.env.SCALEKIT_CLIENT_ID,
  process.env.SCALEKIT_CLIENT_SECRET
);
const redirectUri = process.env.SCALEKIT_REDIRECT_URI;
app.use(cookieParser());

Done when: the client initializes from those env vars.

Step 3 — Login route

Generate a random state per login and keep it in a short-lived HttpOnly cookie. The callback checks it (CSRF).

app.get('/auth/login', (req, res) => {
  const state = randomBytes(32).toString('hex');
  res.cookie('oauthState', state, {
    maxAge: 10 * 60 * 1000,
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    path: '/auth/callback',
  });
  const authorizationUrl = scalekit.getAuthorizationUrl(redirectUri, {
    scopes: ['openid', 'profile', 'email', 'offline_access'],
    state,
  });
  res.redirect(authorizationUrl);
});

Done when: /auth/login sets the oauthState cookie and redirects to that URL with the same state.

Step 4 — Callback and session cookies

Use the same redirectUri as Step 3. Check state and error before the code exchange. Then redirect off /auth/callback.

app.get('/auth/callback', async (req, res) => {
  const { code, error, error_description, state } = req.query;
  const storedState = req.cookies.oauthState;
  res.clearCookie('oauthState', { path: '/auth/callback' });

  if (!state || state !== storedState) {
    return res.redirect('/login?error=invalid_state');
  }
  if (error) {
    console.error('Authentication error:', error, error_description);
    return res.redirect('/login?error=auth_failed');
  }
  if (!code) {
    return res.redirect('/login?error=missing_code');
  }

  const { idToken, accessToken, refreshToken, expiresIn } =
    await scalekit.authenticateWithCode(code, redirectUri);

  res.cookie('accessToken', accessToken, {
    maxAge: (expiresIn - 60) * 1000,
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    path: '/api',
  });
  res.cookie('refreshToken', refreshToken, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    path: '/auth/refresh',
  });
  res.cookie('idToken', idToken, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'lax',
    path: '/',
  });
  res.redirect('/dashboard');
});
Token Purpose
idToken User profile. Keep it for logout.
accessToken Short-lived. Roles and permissions.
refreshToken Long-lived. Used later to renew access.

Do not validate or refresh here. That is manage-saaskit-sessions.

Done when: the callback rejects a missing or mismatched state and an error param, exchanges code, sets the three cookies, and the browser leaves /auth/callback.

Step 5 — Logout

Clear the cookies from Step 4, then redirect to Scalekit. The logout URL is one-time.

app.get('/auth/logout', (req, res) => {
  const idTokenHint = req.cookies.idToken;
  res.clearCookie('accessToken', { path: '/api' });
  res.clearCookie('refreshToken', { path: '/auth/refresh' });
  res.clearCookie('idToken', { path: '/' });
  const postLogoutRedirectUri = `${req.protocol}://${req.get('host')}`;
  const logoutUrl = scalekit.getLogoutUrl({
    idTokenHint,
    postLogoutRedirectUri,
  });
  res.redirect(logoutUrl);
});

Register that same origin as a Post logout URL. Local default is http://localhost:3000.

Done when: cookies are gone and the browser hits the logout URL.

Step 6 — Name the next skill and stop

Name manage-saaskit-sessions for store, validate, refresh, and revoke.

Done when: manage-saaskit-sessions is named, and this skill has stopped.

Reach for

  • setup-saaskit if env or the redirect URI is missing
  • manage-saaskit-sessions to store, validate, refresh, or revoke
  • implement-saaskit-nextjs for Next.js App Router
  • implement-saaskit-python for Django, FastAPI, or Flask
  • references/go.md for Go
  • references/java.md for Spring Boot
  • references/laravel.md for Laravel

Live lookups