@maiguard-hq/id-node
v1.0.3
Published
Server-side code exchange and id_token verification for Continue with MaiGuard ID
Downloads
209
Readme
@maiguard-hq/id-node
The server half of "Continue with MaiGuard ID": exchange the authorization code, and verify what comes back. No dependencies.
npm install @maiguard-hq/id-nodeimport { exchangeCode } from "@maiguard-hq/id-node";
app.post("/auth/maiguard-id", async (req, res) => {
const user = await exchangeCode({
code: req.body.code,
// The browser SDK always sends a code_challenge, so the verifier is required here too.
codeVerifier: req.body.verifier,
clientId: process.env.MAIGUARD_CLIENT_ID,
clientSecret: process.env.MAIGUARD_CLIENT_SECRET,
redirectUri: "https://app.example.com/auth/callback",
});
const account = await db.users.upsert({ maiguardSub: user.sub });
req.session.userId = account.id;
res.json({ ok: true });
});The code comes from your page, where @maiguard-hq/id
renders the button. Use this package on the trusted server where the client secret is stored.
Key the account on sub
sub identifies the person and never changes. email and name describe the profile they selected:
when someone signs in as a business, those are the business's support address and legal name, identical for
every colleague who signs in the same way. Key an account on the email and two colleagues at the same
business land in each other's account.
Use the email to display, and to offer a confirmed link to an existing account. Never a silent merge.
Verification is not optional
exchangeCode verifies the id_token before returning, and there is no flag to skip it. Never trust
claims from an id_token before its signature and required claims have been verified.
Checked: RS256 signature against the issuer's JWKS, iss, aud, exp (60s clock tolerance), and nonce
when you pass one. A token naming an unseen key triggers one JWKS refetch, so key rotation is not an outage.
Verify a token you obtained some other way:
import { verifyIdToken } from "@maiguard-hq/id-node";
const claims = await verifyIdToken(idToken, { clientId, nonce });Public clients
An app with no secret passes codeVerifier instead of clientSecret:
await exchangeCode({ code, clientId, codeVerifier, redirectUri });API
| Call | Purpose |
| --- | --- |
| exchangeCode(options) | Exchange a code, verify the id_token, return the identity |
| verifyIdToken(token, options) | Verify a token on its own |
| getSharedIdentity({ identityGrantId, accessToken }) | Read verified fields the holder shared, when the app requested field scopes |
Every failure throws a MaiGuardIdError with a code: bad_signature, unsupported_alg, bad_issuer,
bad_audience, expired, bad_nonce, unknown_key, malformed_token, token_exchange_failed.
Discovery and JWKS are cached per issuer, so a long-lived server fetches them once.
Docs
https://docs.maiguard.com/maiguard-id-sdk
MIT
