@atcute/oauth-node-client example#
this example demonstrates OAuth authentication for AT Protocol using @atcute/oauth-node-client.
requirements#
confidential OAuth clients must be accessible via https since the authorization server (e.g. Bluesky's PDS) needs to fetch the client's JWKS from the client_id URL.
for local development, use a tunneling service like ngrok, Cloudflare Tunnel, or similar.
setup#
install dependencies:
bun install
create .env.local and generate a fresh private key:
bun run setup:env
then edit .env.local and set PUBLIC_URL to your public https url.
running with ngrok#
- start ngrok tunnel:
ngrok http 3000
-
copy the https URL (e.g.
https://abc123.ngrok.io) -
set
PUBLIC_URLin.env.local, or start the server with the public URL:
PUBLIC_URL=https://abc123.ngrok.io bun run dev
- open the ngrok URL in your browser
environment variables#
PUBLIC_URL(required) - the https URL where this app is accessiblePORT(optional) - local listen port (default:3000)PRIVATE_KEY_JWK(required) - JSON Web Key used for client authentication (private_key_jwt)COOKIE_SECRET(optional) - secret for signed cookies.setup:envgenerates one; if unset, a secret is derived fromPRIVATE_KEY_JWK
generating a private key#
the setup:env script generates a fresh key and writes it into .env.local. to rotate it, run:
bun run setup:env
for production, generate and store a persistent key:
import { generatePrivateKey, exportJwkKey } from '@atcute/oauth-node-client';
const key = await generatePrivateKey('main', 'ES256');
const jwk = await exportJwkKey(key);
console.log(JSON.stringify(jwk));
then set PRIVATE_KEY_JWK to the output.
routes#
/- home page with login form/oauth/login- starts OAuth authorization flow/oauth/callback- OAuth callback handler/protected- example protected resource (fetches session info)/logout- revokes tokens and clears session/client-metadata.json- serves client metadata for discovery/jwks.json- serves client jwks (public keys) for discovery