notlogin-sdk
v0.1.2
Published
Verify Notlogin credentials presented by AI agents. Drop into any TypeScript backend.
Maintainers
Readme
notlogin-sdk
Verify Notlogin credentials presented by AI agents. Five-line integration into any TypeScript backend.
Install
npm i notlogin-sdk viemUse
import { verifyCredential, recordRedemption } from 'notlogin-sdk'
// Anywhere a request from an agent shows up:
const result = await verifyCredential(req.body.vcJson, {
vendorSlug: 'apumail', // your registered slug
requiredProofs: ['email'], // your verified-human bar
// brokerUrl defaults to https://notlogin.com; mode defaults to 'online'
})
if (!result.valid) {
// Either fall back to your anonymous-agent tier or refuse the upgrade.
return res.status(403).json({ reason: result.reason })
}
// You can now trust:
// result.issuer — the user's wallet address that signed this cert
// result.scope — "read" | "write" | "admin"
// result.verifiedProofs — e.g. ["email","wallet"]
// result.budgetUsdcCents — what the user pre-funded
// result.remainingCents — what's still spendable on you
// result.expiresAt
// result.credentialId — needed to call recordRedemption later
const apiKey = mintYourApiKey({ tier: result.verifiedProofs.includes('wallet') ? 'verified' : 'basic' })
// Tell the broker so the budget ledger stays in sync (optional but recommended):
await recordRedemption({
credentialId: result.credentialId!,
vendorSlug: 'apumail',
vendorApiKey: apiKey,
agentLabel: req.headers['x-agent-id']?.toString(),
amountCents: 0, // 0 on first issuance; positive on metered calls
})
return res.json({ apiKey, tier: 'verified-human' })Framework middlewares
Install the peer dependency for your framework, then drop in the middleware:
Express
npm i notlogin-sdk viem expressimport express from 'express'
import { notloginMiddleware } from 'notlogin-sdk/express'
const app = express()
app.use(express.json())
app.post('/agent-action',
notloginMiddleware({ vendorSlug: 'apumail', requiredProofs: ['email'] }),
(req, res) => {
if (!req.notlogin?.valid) return
const { handle, verifiedProofs } = req.notlogin.result
res.json({ handle, verifiedProofs })
}
)Hono
npm i notlogin-sdk viem honoimport { Hono } from 'hono'
import { notloginMiddleware } from 'notlogin-sdk/hono'
const app = new Hono()
app.post('/agent-action',
notloginMiddleware({ vendorSlug: 'apumail', requiredProofs: ['email'] }),
(c) => {
const notlogin = c.get('notlogin')
if (!notlogin.valid) return c.json({ error: 'unauthorized' }, 403)
return c.json({ handle: notlogin.result.handle, verifiedProofs: notlogin.result.verifiedProofs })
}
)Next.js App Router
npm i notlogin-sdk viem nextimport { NextResponse } from 'next/server'
import { withNotlogin } from 'notlogin-sdk/next'
export const POST = withNotlogin(async (req) => {
const notlogin = req.notlogin
if (!notlogin?.valid) return NextResponse.json({ error: 'unauthorized' }, { status: 403 })
return NextResponse.json({
handle: notlogin.result.handle,
verifiedProofs: notlogin.result.verifiedProofs,
})
}, { vendorSlug: 'apumail', requiredProofs: ['email'] })Set rejectOnInvalid: false in any middleware if you want to handle failures yourself.
Verification modes
verifyCredential(vc, { vendorSlug, mode: 'offline' }) // local-only, sub-ms, no revocation check
verifyCredential(vc, { vendorSlug, mode: 'online' }) // default, also checks broker for revoke + budgetonline (default) always calls the broker for revocation + budget, and returns
credentialId + remainingCents (needed for recordRedemption). offline does
local signature/expiry/required-proof checks only — no revocation, no credentialId.
Use offline only when you've recently (<30s) verified the same cert online and
want to skip a round-trip.
What the SDK does
- Fetches the broker's JWKS from
/.well-known/notlogin-issuer.jsonand verifies the Notlogin Ed25519 signature over the canonical credential payload — sub-ms once the JWKS is cached. - Verifies the optional wallet EIP-712 co-signature when present.
- Confirms the cert is addressed to YOUR
vendorSlug(refuses certs for other vendors). - Confirms the cert hasn't expired (
expirationDate). - Enforces your
requiredProofsbar locally. - In
onlinemode (default): posts to the broker's/api/credentials/verifyto catch revocation and get the current budget remaining. - Returns a strongly-typed
{ valid, issuer, scope, verifiedProofs, ... }so your handler can branch on identity strength.
What it deliberately does not do
- It does not call your billing system. After a verified call you may decide to bill the user via x402 or your own rail —
recordRedemptionjust keeps the broker-side ledger accurate. - It does not enforce scope semantics.
read/write/adminis a hint from the user; YOU decide what each means inside your product. - It does not store anything. Stateless module.
Types
See index.ts — VerifyResult, VerifyOptions, NotloginVCJson.
