SETUP GUIDES · SIGN-IN
Sign-in with Claspine on the engine (Node.js, Python, Go)
Your backend hands the sign-in to the Claspine engine, gets a session back and checks it on every request.
With the Claspine engine, sign-in works the same as in Spring Boot, over HTTP. Your login page signs the person in with a sign-in provider; your backend sends the result to the engine with its service key and gets a session; your backend then keeps the session token in a cookie and asks the engine who it belongs to. Node.js has ready-made helpers in @grahmur-org/claspine-client; other languages call the same three endpoints.
Words you’ll see
- Sign-in provider
- The service that checks who a person is: Firebase Authentication (email and password, Google, Apple, phone), or Claspine’s own one-time codes sent by SMS, WhatsApp or email. Claspine trusts its answer and opens a session.
- ID token
- A short-lived signed message from the sign-in provider that says “this is user X”. Your app gets it after the person signs in and hands it to Claspine once, in exchange for a session.
- Session
- What keeps a person signed in. Claspine gives your app a session token after sign-in; every later request carries it. Claspine checks it, ends it at sign-out, and can end every session of a person at once.
Before you start
- The engine running (see Run the Claspine engine) and a service key for your backend.
- For email/password or Google: a Firebase project with those methods switched on. For codes: your own SMS/WhatsApp or email provider.
Steps
- Give the engine your Firebase project:
SPINE_FIREBASE_PROJECT_ID=my-firebase-project. For codes addSPINE_PHONE_CODE_SIGN_IN=trueand/orSPINE_EMAIL_CODE_SIGN_IN=true. Restart the engine. - Your login page signs the person in with the Firebase SDK and sends the ID token to your backend (for example
POST /login). The browser never talks to the engine. - Your backend exchanges it:
spine.auth.exchangeCredential({ provider: 'firebase-auth', credential: idToken }), orPOST /api/v1/auth/sessionswith the headersX-Spine-Api-KeyandX-Spine-Host. Store the returnedsessionTokenin an httpOnly cookie namedgrahmur_session. - Protect your routes: in Express add
createClaspineMiddleware({ client: spine, publicPaths: ['/login'] }); every request then hasreq.spine.account, or answers 401. Other languages callGET /api/v1/auth/mewithAuthorization: Bearer <session token>and treat 401 as signed out. - Sign out:
DELETE /api/v1/auth/sessions/currentwith the session token, then clear the cookie. - Codes instead of passwords: your backend calls
spine.auth.requestCode({ provider: 'phone-code', destination: '+4912345678' }), the person types the code, thenexchangeCredential({ provider: 'phone-code', credential: `${challengeId}:${code}` }).
import express from 'express';
import cookieParser from 'cookie-parser';
import { ClaspineClient, createClaspineMiddleware } from '@grahmur-org/claspine-client';
const spine = new ClaspineClient({
baseUrl: process.env.SPINE_API_URL, // the engine, on your private network
apiKey: process.env.SPINE_API_KEY, // service key: stays on the server
tenantHost: 'app.example.com', // one of SPINE_HOSTS
});
const app = express().use(express.json()).use(cookieParser());
app.post('/login', async (req, res) => {
const session = await spine.auth.exchangeCredential({ provider: 'firebase-auth', credential: req.body.idToken });
res.cookie('grahmur_session', session.sessionToken, { httpOnly: true, secure: true, sameSite: 'lax' });
res.sendStatus(204);
});
app.use(createClaspineMiddleware({ client: spine, publicPaths: ['/login', '/health'] }));
app.get('/api/me', (req, res) => res.json(req.spine!.account)); What goes where in Claspine
| Console field | Value |
|---|---|
| SPINE_FIREBASE_PROJECT_ID | Firebase console → Project settings → General → Project ID. |
| Session cookie | grahmur_session, httpOnly, secure, sameSite lax: the SDK middleware reads it (or an Authorization: Bearer header from mobile apps). |
Keep it safe
- The service key never leaves your backend; browsers and mobile apps only ever hold their own session token.
- Keep the engine on a private network. Your backend is the only thing that calls it.
- Set SPINE_ENVIRONMENT to PRODUCTION for real users: sandbox sign-in is then refused.
Claspine stores the values encrypted, never shows them again in full, and never sends them to your app or SDK.
If something goes wrong
- exchangeCredential answers 404 HOST_NOT_AVAILABLE.
- Set tenantHost (X-Spine-Host) to one of SPINE_HOSTS.
- exchangeCredential answers 401.
- The ID token is from another Firebase project or expired; check SPINE_FIREBASE_PROJECT_ID and get a fresh token.
- Every route answers 401 UNAUTHENTICATED.
- The cookie is not reaching your backend: add cookie-parser, and send fetch requests with credentials: 'include'.