Nastardocs v1 · API v1

Last updated 2026-09-22

Security

How authentication, sessions, and setup tokens actually work today — not a compliance claim. Nastar makes no certification or legal compliance claims; this page documents mechanism, not attestation.

Email + OTP login

  • No passwords. A 6-digit code, cryptographically random (crypto.randomInt), valid for 10 minutes.
  • Stored as an HMAC-SHA256 hash (server secret + code), never in plaintext, alongside a hash of the requesting email and IP.
  • Single-use: verification atomically consumes the challenge with an UPDATE ... WHERE consumed_at IS NULL RETURNING — a race between two verify requests for the same code can only succeed once.
  • Up to 5 wrong-code attempts per challenge before it's locked out; a fresh request issues a new challenge.
  • Verify and request responses are generic ("invalid or expired code" / "rate limited") — they don't reveal whether an email address has an account, to avoid enumeration.

Rate limits

LimitValue
Resend cooldown60 seconds
Requests per email address / hour5
Requests per IP address / hour20

Sessions

  • Cookie name nastar_session, 30-day expiry, HttpOnly, SameSite=Lax, Secure on every deployment served over HTTPS.
  • A new session is issued on every successful OTP verification; POST /v1/auth/logout revokes it server-side, not just client-side cookie deletion.
  • Every device you're signed in on is a separate session row — the account page lists them all and can revoke any one individually (GET/DELETE /v1/auth/sessions), without logging out your other devices.

CORS and CSRF

  • Cookie-authenticated routes (/v1/auth, /v1/organizations, /v1/sites) allow only the configured DASHBOARD_ORIGIN, with credentials.
  • Public and docs routes (/v1/public/*, /v1/docs, /v1/openapi.json) allow any origin — they carry no credentials, so there's nothing to protect.
  • All mutating requests must be Content-Type: application/json; non-JSON mutation attempts are rejected before reaching any handler, which also blocks simple cross-site form submissions from acting as CSRF vectors against session routes.

Setup tokens

  • Format nst_..., hashed at rest the same way as OTP codes (HMAC-SHA256), never stored or logged in plaintext.
  • Shown once, at creation, in the dashboard response — not retrievable again afterward, even by an org admin.
  • Bound to one organization and, optionally, one site; carries an explicit subset of sites:read / sites:write / sites:publish.
  • Only organization admins can create, list, or revoke tokens.
  • Revoked or expired tokens are rejected with 401 on every /v1/agent/* route immediately — no caching of validity.

Invites

  • Single-use tokens (nvt_...), hashed at rest the same way as OTP codes and setup tokens, expiring after 7 days.
  • Only organization admins can send or revoke an invite.
  • Accepting requires being signed in as the exact invited email — logging in with a different account shows a mismatch instead of silently granting access.
  • Re-inviting the same address replaces its earlier pending invite rather than leaving both valid.

Tenant isolation

Applied consistently across organizations, sites, and tokens:

  • Not a member of the organization at all → 404 (the resource's existence isn't revealed to non-members).
  • A member, but the action needs a role/scope you don't have → 403.

A setup token bound to a specific site is rejected with 403 on any other site, even within the same organization.

Consent gating

The SDK fails closed: if the published config can't be fetched, or stored consent is malformed or version-mismatched, every optional category is treated as not consented — see SDK reference for the full contract.

What isn't built yet

  • No OAuth device flow or MCP server for automation — a scoped setup token created manually in the dashboard is the only automation credential today. This is an intentional scope decision, not an oversight.
  • No 2FA beyond the OTP login itself (there's no separate password to protect).
  • No public security disclosure process or bug bounty yet — the service is deployed and serving, but no intake channel for reports has been set up.