@nya-account/node-sdk
v2.1.0
Published
Official Node.js SDK for Nya Account SSO — OAuth 2.1 / OIDC client with PKCE, JWT verification, and Express middleware
Maintainers
Readme
@nya-account/node-sdk
Official Node.js SDK for Nya Account SSO system.
Provides a complete OAuth 2.1 / OIDC client with PKCE, JWT verification, and Express middleware.
Installation
npm install @nya-account/node-sdk
# or
pnpm add @nya-account/node-sdk
# or
yarn add @nya-account/node-sdkQuick Start
The production issuer is built in — a minimal setup only needs the client ID, client secret, and redirect URI:
import { NyaAccountClient } from '@nya-account/node-sdk'
const client = new NyaAccountClient({
clientId: 'my-app',
clientSecret: 'my-secret',
redirectUri: 'https://myapp.com/callback',
scope: 'openid profile email'
})
// Create authorization URL (with PKCE)
const { url, codeVerifier, state } = await client.createAuthorizationUrl()
// Exchange code for tokens
const tokens = await client.exchangeCode({
code: callbackCode,
codeVerifier
})
// Get user info
const userInfo = await client.getUserInfo(tokens.accessToken)
// Revoke refresh token on logout
await client.revokeToken(tokens.refreshToken, { tokenTypeHint: 'refresh_token' })
// Build RP-initiated logout URL
const logoutUrl = await client.createEndSessionUrl({
idTokenHint: tokens.idToken,
postLogoutRedirectUri: 'https://myapp.com/logout/callback',
state: 'logout-csrf-state'
})To use a different environment (e.g. self-hosted), pass issuer explicitly — see Service Endpoints.
Public clients (no client secret)
For applications that cannot keep a secret (CLIs, desktop apps), register the client as a public client and set tokenEndpointAuthMethod: 'none'. PKCE is always enforced:
const client = new NyaAccountClient({
clientId: 'my-cli',
tokenEndpointAuthMethod: 'none',
redirectUri: 'http://127.0.0.1:8976/callback'
})Note: token introspection requires a confidential client and is not available with 'none'.
Express Middleware
import express from 'express'
import { NyaAccountClient } from '@nya-account/node-sdk'
import { getAuth } from '@nya-account/node-sdk/express'
const app = express()
const client = new NyaAccountClient({
clientId: 'my-app',
clientSecret: 'my-secret'
})
// Protect all /api routes
app.use('/api', client.authenticate())
app.get('/api/me', (req, res) => {
const auth = getAuth(req)
res.json({ userId: auth?.sub, scopes: auth?.scope })
})
// Require specific scopes
app.get(
'/api/profile',
client.authenticate(),
client.requireScopes('profile'),
(req, res) => {
const auth = getAuth(req)
res.json({ name: auth?.sub })
}
)
// Use introspection for sensitive operations
app.post('/api/sensitive', client.authenticate({ strategy: 'introspection' }), handler)Configuration
| Option | Type | Default | Description |
| ------------------------- | ---------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| issuer | string | 'https://account-api.edge.api.liyxi.com' | SSO service URL (Issuer URL). See Service Endpoints for available endpoints. |
| clientId | string | required | OAuth client ID |
| clientSecret | string | required for confidential clients | OAuth client secret. Omit it for public clients (tokenEndpointAuthMethod: 'none') |
| redirectUri | string | — | Default redirect URI, used when the call options don't provide one |
| scope | string | 'openid' | Default scopes for authorization requests, space-separated |
| tokenEndpointAuthMethod | string | 'client_secret_post' | Client authentication method: 'client_secret_post', 'client_secret_basic', or 'none' (public client) |
| timeout | number | 10000 | HTTP request timeout in milliseconds |
| discoveryCacheTtl | number | 3600000 | Discovery document cache TTL in milliseconds (default: 1 hour) |
| endpoints | EndpointConfig | — | Explicitly specify endpoint URLs (auto-discovered via OIDC Discovery if omitted) |
API Reference
NyaAccountClient
Authorization
createAuthorizationUrl(options?)— Create an OAuth authorization URL with PKCEvalidateAuthorizationCallback(options)— Validate callback params (state / RFC 9207 iss / error response)pushAuthorizationRequest(options?)— Push authorization request to PAR endpoint (RFC 9126)createAuthorizationUrlWithPar(options?)— Create authorization URL using PARrequest_uri
Device Authorization Grant (RFC 8628)
deviceAuthorization(options?)— Start a device flow, returnsuserCode/verificationUripollDeviceToken(options)— Poll the token endpoint until the user approves (handlesauthorization_pending/slow_down)
Token Operations
exchangeCode(options)— Exchange an authorization code for tokensrefreshToken(refreshToken)— Refresh an Access TokenrevokeToken(token, options?)— Revoke a token (RFC 7009)introspectToken(token, options?)— Token introspection (RFC 7662, confidential clients only)
User Info
getUserInfo(accessToken)— Get user info via OIDC UserInfo endpoint
JWT Verification
verifyAccessToken(token, options?)— Locally verify a JWT Access Token (RFC 9068)verifyIdToken(token, options?)— Locally verify an OIDC ID TokenverifyLogoutToken(token, options?)— Verify an OIDC Back-Channel Logout Token
Express Middleware
authenticate(options?)— Middleware to verify Bearer Token (localorintrospectionstrategy)requireScopes(...scopes)— Middleware to validate token scopes
Cache
discover()— Fetch OIDC Discovery document (cached with TTL)clearCache()— Clear Discovery and JWT verifier cache
OIDC Logout
createEndSessionUrl(options?)— Create OIDC RP-initiated logout URL (end_session_endpoint)
Back-Channel Logout
If your client registers a backchannel_logout_uri, the server POSTs a logout_token there whenever the user's SSO session ends. Verify it and terminate the matching local session:
app.post(
'/oidc/backchannel-logout',
express.urlencoded({ extended: false }),
async (req, res) => {
try {
const payload = await client.verifyLogoutToken(req.body.logout_token)
// Terminate local sessions by payload.sub and/or payload.sid
await destroySessions({ userId: payload.sub, sessionId: payload.sid })
res.status(200).end()
} catch {
res.status(400).json({ error: 'invalid_request' })
}
}
)Express Helpers
Available from @nya-account/node-sdk/express:
getAuth(req)— Retrieve the verified Access Token payload from a requestextractBearerToken(req)— Extract Bearer token from the Authorization headersendOAuthError(res, statusCode, error, errorDescription)— Send an OAuth-standard error response
PKCE Utilities
generatePkce()— Generate a code_verifier and code_challenge pairgenerateCodeVerifier()— Generate a PKCE code_verifiergenerateCodeChallenge(codeVerifier)— Generate an S256 code_challenge
Error Handling
The SDK provides typed error classes:
import {
NyaAccountError, // Base error class
OAuthError, // OAuth protocol errors from the server
TokenVerificationError, // JWT verification failures
DiscoveryError // OIDC Discovery failures
} from '@nya-account/node-sdk'
try {
await client.verifyAccessToken(token)
} catch (error) {
if (error instanceof TokenVerificationError) {
console.log(error.code) // 'token_verification_failed'
console.log(error.description) // Human-readable description
}
}Requirements
- Node.js >= 20.0.0
- Express 4.x or 5.x (optional, for middleware features)
