@nexartis/sentinel-sdk
Passwordless, magic-link authentication for SvelteKit. A batteries-included client SDK for the hosted Nexartis Sentinel auth backend — five lines in
hooks.server.ts, three lines in your auth route, and you're done.
Sentinel is a passwordless authentication service: users sign in with a one-time magic link delivered to their email, the SDK handles JWT issuance, secure cookie storage, automatic token refresh, and route protection. No passwords. No sessions to reap. No boilerplate.
Table of contents
- What you get
- Install
- Configure
- Quickstart
- Subpath exports
- Hosted Sentinel (optional)
- Framework support
- Versioning
- License
What you get
- Framework-agnostic core —
SentinelClient, local JWT decode, expiry checks, structured errors, retry classification. - SvelteKit
handlehook — JWT validation, automatic refresh on stale access tokens, route protection,event.locals.userhydration. - Drop-in API handlers —
createAuthHandlers()mounts login / register / poll / claim / refresh / logout on a single catch-all+server.ts. - Page handlers —
handleMagicLink,handleVerifyEmail,handleVerifiedfor the browser-side magic-link flow. - Authenticated fetch —
authFetch/authFetchJsonfor long-running client operations with transparent token refresh. - Launch primitives —
onBeforeLogingating,resolveRedirectfor role-aware post-login destinations, configurablelogoutRedirect. - Cookie management — HTTP-only,
Secure,SameSite=Laxcookies with rotation on refresh. - TypeScript-first — ships
.d.tsand sourcemaps.
Install
pnpm add @nexartis/sentinel-sdk
# or
npm install @nexartis/sentinel-sdk
# or
yarn add @nexartis/sentinel-sdk
Requirements
- Node.js ≥ 20
- SvelteKit ≥ 2.0 (optional peer — only needed for the
/sveltekit*subpath exports) - A running Sentinel backend (self-hosted, or the free hosted tier — see below).
Configure
The SDK does not bake in any backend URL. Every request is directed at the URL you configure. Two values drive everything:
| Name | Purpose |
|---|---|
apiUrl |
Base URL of the Sentinel auth backend (e.g. https://auth.example.com). |
baseUrl |
Public base URL of your own app (e.g. https://app.example.com) — used when constructing magic-link callback URLs. |
Expose them via SvelteKit environment ($env/static/private for apiUrl, $env/static/public for the browser-visible base URL) and pass them into createSentinelHandle as top-level apiUrl / baseUrl options. createAuthHandlers reads the same values from event.platform.env.SENTINEL_API_URL / VITE_BASE_URL at request time and takes no URL options directly.
# .env
SENTINEL_API_URL="https://auth.example.com"
PUBLIC_BASE_URL="https://app.example.com"
Quickstart
1. Protect routes with the SvelteKit hook
// src/hooks.server.ts
import { createSentinelHandle } from '@nexartis/sentinel-sdk/sveltekit';
import { SENTINEL_API_URL } from '$env/static/private';
import { PUBLIC_BASE_URL } from '$env/static/public';
export const handle = createSentinelHandle({
apiUrl: SENTINEL_API_URL,
baseUrl: PUBLIC_BASE_URL,
protectedRoutes: ['/dashboard', '/admin'],
loginRedirect: '/auth'
});
After this hook runs, event.locals.user is populated on every request with { isAuthenticated, id, email, roles }.
2. Mount the auth API
// src/routes/api/auth/[...path]/+server.ts
import { createAuthHandlers } from '@nexartis/sentinel-sdk/sveltekit/handlers';
export const { GET, POST } = createAuthHandlers({
// Optional: gate logins BEFORE the magic link is dispatched.
onBeforeLogin: async (_event, { email }) => {
if (await isBlocked(email)) {
return { error: 'not_allowed', status: 403, redirect: '/waitlist' };
}
},
// Optional: role-aware post-login destination.
resolveRedirect: async (_event, { user, requestedRedirect, defaultRedirect }) =>
user.roles.includes('admin') ? '/admin' : (requestedRedirect || defaultRedirect),
// Optional: where to land after logout.
logoutRedirect: '/'
});
3. Handle the magic link
// src/routes/auth/magic/+page.server.ts
import { handleMagicLink } from '@nexartis/sentinel-sdk/sveltekit/pages';
export const load = handleMagicLink;
// src/routes/auth/verify/+page.server.ts
import { handleVerifyEmail } from '@nexartis/sentinel-sdk/sveltekit/pages';
export const load = handleVerifyEmail;
// src/routes/auth/verified/+page.server.ts
import { handleVerified } from '@nexartis/sentinel-sdk/sveltekit/pages';
export const load = handleVerified;
4. Call your own APIs with automatic refresh
// Any client component
import { authFetchJson } from '@nexartis/sentinel-sdk/sveltekit/client';
const profile = await authFetchJson<UserProfile>('/api/me');
authFetch / authFetchJson transparently refresh the access token if it has expired mid-request, so long-running client operations don't fall over on a stale JWT.
Subpath exports
The package ships one framework-agnostic core and one SvelteKit adapter, split into focused subpaths so you only pay for what you import.
| Export | Purpose |
|---|---|
@nexartis/sentinel-sdk/core |
Framework-agnostic client: SentinelClient, decodeTokenLocally, validateToken, isTokenExpired, SentinelError, SentinelCode, createLogger, plus every response type. |
@nexartis/sentinel-sdk/sveltekit |
createSentinelHandle and cookie utilities (setSessionCookies, getSessionCookies, clearAuthCookies, COOKIE_NAMES). |
@nexartis/sentinel-sdk/sveltekit/handlers |
createAuthHandlers() — the catch-all API route. |
@nexartis/sentinel-sdk/sveltekit/pages |
handleMagicLink, handleVerifyEmail, handleVerified for browser-side flows. |
@nexartis/sentinel-sdk/sveltekit/client |
authFetch, authFetchJson for authenticated client-side requests. |
Framework-agnostic core in action
import { SentinelClient, decodeTokenLocally, isTokenExpired } from '@nexartis/sentinel-sdk/core';
const client = new SentinelClient({
apiUrl: 'https://auth.example.com',
baseUrl: 'https://app.example.com',
timeoutMs: 8000,
maxRetries: 1
});
const decoded = decodeTokenLocally(accessToken);
if (isTokenExpired(accessToken)) {
// ... refresh via client.refresh(refreshToken)
}
Hosted Sentinel (optional)
Nexartis operates a hosted Sentinel backend so you don't have to.
- Free tier for reasonable use — hobby projects, small teams, side projects, indie apps.
- Enterprise support available for higher volumes, SLAs, custom domains, dedicated infrastructure, and compliance workloads.
Either way, this SDK is fully self-service and works against any Sentinel-compatible backend, including your own.
Learn more and get in touch: https://cubicube.com
Framework support
| Framework | Status |
|---|---|
| SvelteKit ≥ 2.0 (Svelte 5) | First-class |
| Framework-agnostic core | Use anywhere — Node, Bun, Cloudflare Workers, browsers |
| Next.js / Remix / Nuxt / SolidStart | Roadmap — core is designed to make new adapters straightforward |
Contributions of new adapters are welcome under the same Apache-2.0 license.
Versioning
This SDK follows Semantic Versioning and a strict never-break-minor policy: minor and patch releases are always safe to auto-update; breaking changes are reserved for majors and preceded by at least one deprecation cycle. See VERSIONING.md and CHANGELOG.md.
License
Licensed under the Apache License 2.0. Copyright Nexartis LLC.
You may use, modify, and redistribute this SDK freely in commercial and non-commercial projects. The Sentinel hosted backend is a separate service governed by its own terms — see https://cubicube.com.