Skip to main content

Who Signed In, in Your Code

On every request, the platform hands the application the identity of who signed in, signed. The SDK checks it and returns the person; in another language, the check is the same and is described below.

TypeScript and Node​

npm install @nnumbers/zero
import { NNumbers, UnauthenticatedError } from '@nnumbers/zero/app'

const nn = NNumbers.init() // reads the NNUMBERS_* variables

app.get('/api/me', async (req, res) => {
res.json({ user: await nn.auth.user(req) }) // the person, or null
})

app.get('/dashboard', async (req, res) => {
try {
const user = await nn.auth.requireUser(req, req.url)
res.send(`Hello, ${user.name ?? user.username}`)
} catch (e) {
if (e instanceof UnauthenticatedError) return res.redirect(e.loginPath)
throw e
}
})
APIWhat it does
NNumbers.init()the application context: appId, org and auth
nn.auth.user(req)who signed in, or null
nn.auth.requireUser(req, returnTo)like user, but without a person it throws UnauthenticatedError with the loginPath that returns to returnTo
nn.auth.loginPath(returnTo)the sign-in path; a destination outside the application becomes /
nn.auth.logoutPaththe sign-out path (POST)
ErrorCodeWhen
AppConfigurationErrorORGANIZATION_IAM_NOT_ENABLEDthe application runs without the capability on, or outside Zero
UnauthenticatedErrorUSER_SESSION_REQUIREDthe route requires someone and no one signed in
IdentityAssertionErrorIDENTITY_ASSERTION_INVALIDan identity arrived that does not check out — it never becomes a person

user accepts the Node request, a fetch Request or a headers object. There is a complete example, without a framework, in examples/organization-iam in the SDK repository.

In Another Language​

The identity arrives in the X-NNumbers-Identity header: a compact JWS, algorithm ES256, typ nn-identity+jwt. Check it always, on every request — a header whose signature was not checked proves nothing:

  1. The signature, with the public keys at the address in NNUMBERS_IDENTITY_JWKS. Keep the keys for a few minutes and fetch them again when an unknown kid arrives.
  2. iss equal to NNUMBERS_IDENTITY_ISSUER.
  3. aud equal to NNUMBERS_APP_ID — an identity handed to another application is not valid here.
  4. org equal to NNUMBERS_ORG_ID.
  5. exp and nbf: the identity is valid for 5 minutes.

Without the header, the request is anonymous. With the header and any check failing, refuse it — never treat it as a person.

ClaimWhat it is
subthe person's identifier in the organization's IAM
org, org_slugthe organization
iamthe address of the organization's IAM
sidthe session reference
name, email, email_verified, preferred_usernamewhen the account has them
iat, nbf, exp, jtithe validity and the identifier of this identity

The Platform Variables​

With the capability on, the deployment injects:

VariableWhat it is
NNUMBERS_APP_IDthis application's id (svc_…)
NNUMBERS_ORG_ID, NNUMBERS_ORG_SLUGthe project's organization
NNUMBERS_IDENTITY_ISSUERthe identity issuer
NNUMBERS_IDENTITY_JWKSthe address of the public keys — reachable only from inside the platform
NNUMBERS_BROKER_URLwhere the application asks for the person's credential for QueryMesh — reachable only from inside the platform

The NNUMBERS_ prefix belongs to the platform: the service configuration does not accept a variable with it.

Next Steps​