Authentication

SpaceNode provides a declarative auth system. You define your verification logic once, the framework provides the guard.

Two Ways to Define Auth

1. Global: defineAuth()

Call once in your entry point. Applies to all apps:

import { createApp, defineAuth } from 'SpaceNode'

defineAuth(async (token) => {
  // token = extracted from "Bearer TOKEN" header
  // Return user object if valid, null if invalid

  const session = await Session.findOne({ token, active: true })
  if (!session) return null

  const user = await User.findById(session.userId)
  return user
    ? { id: user.id, name: user.name, role: user.role }
    : null
})

const app = await createApp()

2. Per-App: app.setAuth()

Each app instance can have its own auth verifier. Overrides the global defineAuth() for that app. The verifier receives the token and optionally the request context (useful for multi-tenant auth):

const app = await createApp()

app.setAuth(async (token, request) => {
  try {
    return jwt.verify(token, process.env.JWT_SECRET)
  } catch {
    return null
  }
})

app.listen(3000)
Request context in verifier — The second argument request gives you access to headers, IP, cookies, and more. This is useful for multi-tenant auth where you need request context to determine which tenant's credentials to verify against.
Resolution order — When the auth guard runs, it first checks for a per-app verifier (app.setAuth()). If none is set, it falls back to the global defineAuth() verifier.

Using the Auth Guard

Once defined, use 'auth' in any route's pipe array:

routes: [
  ['GET',  '/me',      'me',       ['auth']],
  ['POST', '/logout',  'logout',   ['auth']],
  ['GET',  '/admin',   'admin',    ['auth', 'role:admin']],
]

What Happens Under the Hood

  1. Client sends Authorization: Bearer TOKEN header
  2. Auth guard extracts the token
  3. Guard calls per-app verifier (app.setAuth()) or global verifier (defineAuth())
  4. If verifier returns null401 Unauthorized
  5. If verifier returns a user object → merged into request
  6. Handler can access request.user directly

JWT Example

import jwt from 'jsonwebtoken'

defineAuth(async (token) => {
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET)
    return { id: payload.sub, role: payload.role }
  } catch {
    return null
  }
})
Framework agnostic — SpaceNode doesn't care how you verify tokens — JWT, sessions, API keys, OAuth. You provide the logic, the framework provides the plumbing.