Astro
Scalekit & Astro
Scalekit & Astro
Scalekit is an authentication platform built for B2B and AI applications. It provides social login, enterprise SSO, magic links, and more — managing the full OAuth 2.0 / OIDC flow so you get back tokens and a user profile without building any login UI. A single Scalekit environment supports multiple applications (for example, app.yourcompany.com and docs.yourcompany.com), so your users authenticate once and share the same session across all your properties.
Initializing Scalekit in Astro
Prerequisites
- A Scalekit account and environment. If you don't have one, you can sign up for free at scalekit.com and create a new environment.
- An Astro project with
output: 'server'for on-demand rendering enabled. - Scalekit credentials for your environment. You can find these in the Settings > API Credentials section of your Scalekit dashboard.
SCALEKIT_ENVIRONMENT_URL: The URL of your Scalekit environment.SCALEKIT_CLIENT_ID: Your Scalekit client ID.SCALEKIT_CLIENT_SECRET: Your Scalekit client secret.SCALEKIT_REDIRECT_URI: The callback URL Scalekit will redirect to after login (e.g.http://localhost:4321/api/auth/callback). Register this in your Scalekit dashboard under Settings > Redirects.
Adding Scalekit credentials
To add your Scalekit credentials to your Astro project, add the following to your .env file:
SCALEKIT_ENVIRONMENT_URL=YOUR_SCALEKIT_ENVIRONMENT_URL
SCALEKIT_CLIENT_ID=YOUR_SCALEKIT_CLIENT_ID
SCALEKIT_CLIENT_SECRET=YOUR_SCALEKIT_CLIENT_SECRET
SCALEKIT_REDIRECT_URI=http://localhost:4321/api/auth/callback
Now, these environment variables are available in your project.
If you would like to have IntelliSense for your environment variables, edit or create the env.d.ts in your src/ directory and add the following:
/// <reference types="astro/client" />
interface ImportMetaEnv {
readonly SCALEKIT_ENVIRONMENT_URL: string;
readonly SCALEKIT_CLIENT_ID: string;
readonly SCALEKIT_CLIENT_SECRET: string;
readonly SCALEKIT_REDIRECT_URI: string;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
declare namespace App {
interface Locals {
user?: {
sub: string;
email?: string;
name?: string;
};
}
}
.env files in Astro.
Your project should now include these files:
Installing dependencies
To connect to Scalekit, install @scalekit-sdk/node in your project.
Next, create a folder named lib in your src/ directory and add a Scalekit client file:
Now, your project should include these files:
Adding authentication with Scalekit
Scalekit handles authentication through a standard OAuth 2.0 / OIDC redirect flow. Your app sends users to Scalekit, they sign in, and Scalekit redirects them back to your callback URL with an authorization code you exchange for tokens. This guide uses the Authorization Code flow with a client secret, which is appropriate for server-side rendered applications.
:::tip If you prefer not to use a client secret, Scalekit also supports the PKCE flow. The Scalekit developer docs site is an open-source Astro project that demonstrates a full PKCE implementation without an SDK. :::
Creating auth server endpoints
To add authentication to your project, you will need to create three server endpoints:
GET /api/auth/login: redirects users to Scalekit to sign in.GET /api/auth/callback: exchanges the authorization code for tokens and sets session cookies.GET /api/auth/logout: clears session cookies and ends the Scalekit session.
Create these endpoints in the src/pages/api/auth/ directory of your project. Your project should now include these new files:
login.ts generates an authorization URL and redirects the user to Scalekit to sign in.
return Response.redirect(url);
};
callback.ts receives the authorization code from Scalekit, exchanges it for tokens, and stores them in HttpOnly cookies.
const code = url.searchParams.get("code");
if (!code) {
return Response.redirect(new URL("/", request.url).origin);
}
const { user, idToken, accessToken, refreshToken } =
await scalekit.authenticateWithCode(code, REDIRECT_URI);
const secure = url.protocol === "https:";
const cookieOptions = { httpOnly: true, path: "/", sameSite: "lax" as const, secure };
cookies.set("sk-id-token", idToken, cookieOptions);
cookies.set("sk-access-token", accessToken, cookieOptions);
cookies.set("sk-refresh-token", refreshToken, cookieOptions);
return Response.redirect(new URL("/", request.url).origin);
};
logout.ts clears the session cookies and redirects to Scalekit's logout endpoint to end the Scalekit session.
cookies.delete("sk-id-token", { path: "/" });
cookies.delete("sk-access-token", { path: "/" });
cookies.delete("sk-refresh-token", { path: "/" });
const logoutUrl = scalekit.getLogoutUrl({
idTokenHint: idToken,
postLogoutRedirectUri: new URL("/", request.url).origin,
});
return Response.redirect(logoutUrl);
};
:::note
The postLogoutRedirectUri passed to getLogoutUrl() must be registered as an allowed post-logout redirect URI in your Scalekit dashboard, otherwise Scalekit will reject the logout request.
:::
Adding session middleware
Create a src/middleware.ts file to validate the access token on every request and populate Astro.locals.user with the authenticated user's profile. When the access token has expired, the middleware automatically refreshes it using the refresh token.
if (accessToken) {
try {
const claims = await scalekit.validateToken<IdTokenClaim>(accessToken);
context.locals.user = {
sub: claims.sub,
email: claims.email,
name: claims.name,
};
} catch {
// Access token invalid or expired — try to refresh
const refreshToken = context.cookies.get("sk-refresh-token")?.value;
if (refreshToken) {
try {
const { accessToken: newToken } =
await scalekit.refreshAccessToken(refreshToken);
const secure = new URL(context.request.url).protocol === "https:";
context.cookies.set("sk-access-token", newToken, {
httpOnly: true,
path: "/",
sameSite: "lax",
secure,
});
const claims = await scalekit.validateToken<IdTokenClaim>(newToken);
context.locals.user = {
sub: claims.sub,
email: claims.email,
name: claims.name,
};
} catch {
// Refresh failed — clear session cookies
context.cookies.delete("sk-id-token", { path: "/" });
context.cookies.delete("sk-access-token", { path: "/" });
context.cookies.delete("sk-refresh-token", { path: "/" });
}
}
}
}
return next();
});
Creating an authenticated page
Now that your middleware populates Astro.locals.user, you can create pages that show different content based on authentication state.
dashboard.astro is a page that is only accessible to authenticated users. It reads the user from Astro.locals, set by the middleware, and redirects to the home page if the user is not signed in.
---
const user = Astro.locals.user;
if (!user) {
return Astro.redirect("/");
}
---
<Layout title="Dashboard">
<h1>Welcome, {user.name ?? user.email}</h1>
<p>You are signed in.</p>
<a href="/api/auth/logout">Sign out</a>
</Layout>