Node
The server-side model — a secret key, and a token verified per request.
This page is the framework-free version: what the server client does and why. Express and Fastify wire the same calls into their own idioms.
A server never holds one user's session. It holds a secret key, and verifies the token each request arrives with.
Install
npm install @nulvless/nulvless-jsCreate the client
import { createServerClient } from '@nulvless/nulvless-js';
export const nulvless = createServerClient(
process.env.NULVLESS_URL!,
process.env.NULVLESS_SECRET!,
);There is no storage option here — persistence is a browser concern. One client
serves every request; it holds no per-user state.
Verify the caller
verify answers two questions at once: is this token still good, and does the
holder have the permission you named. Ask both in one call rather than fetching
a user and deciding yourself.
import { nulvless } from './nulvless';
export async function authenticate(token: string | undefined) {
if (!token) return null;
const { data, error } = await nulvless.auth.verify(undefined, {
headers: { Authorization: `Bearer ${token}` },
});
return error ? null : data;
}Passing undefined as the first argument checks the token only. To also require
a role on a resource:
const { error } = await nulvless.auth.verify(
{ resource: orgId, roles: ['owner', 'admin'] },
{ headers: { Authorization: `Bearer ${token}` } },
);Read the token off the request
Nothing in the SDK reads your request object for you, because the shape differs per runtime.
// Web Request — Next.js App Router, Deno, Workers
const token = request.headers.get('authorization')?.replace('Bearer ', '');
// Node IncomingMessage — Express, Fastify (via request.raw), http.createServer
const token = req.headers.authorization?.replace('Bearer ', '');Act on the user's behalf
When the server does something for a user — sending an invitation, for instance — forward their headers so the record reflects their device and not your infrastructure.
import { forwardUserHeaders } from '@nulvless/nulvless-js';
await nulvless.auth.grants.invite(
{ invites: [{ email, role_id: roleId }], resource: orgSlug },
{ headers: forwardUserHeaders(request) },
);forwardUserHeaders accepts a Web Request or anything shaped like a Node
IncomingMessage, so the same call works across runtimes.
Send a message
await nulvless.comms.email.send({
to: '[email protected]',
template: 'grants-invite',
language: 'pt-BR',
params: { organization: 'Acme Inc', role: 'admin' },
});A plain http server
No framework at all, to show there is nothing hidden:
import { createServer } from 'node:http';
import { nulvless } from './lib/nulvless';
createServer(async (req, res) => {
const token = req.headers.authorization?.replace('Bearer ', '');
const { data, error } = await nulvless.auth.verify(undefined, {
headers: { Authorization: `Bearer ${token}` },
});
if (error) {
res.writeHead(401).end();
return;
}
res.writeHead(200, { 'content-type': 'application/json' });
res.end(JSON.stringify({ user: data.user.id }));
}).listen(3000);Requiring a fresh confirmation
For a destructive route, require sudo. The browser calls
auth.sessions.sudo(), the user types the code, and the browser sends that code
as a header. Your handler only passes it through.
const { error } = await nulvless.auth.sessions.revoke({ id: sessionId, nonce });See Sudo mode.