- Published on
NetSuite M2M access token
Exchanges a PS256-signed JWT for a 60-minute NetSuite access token, and caches it until two minutes before expiry.
netsuite-m2m.js
import crypto from 'node:crypto'
const b64url = (input) => Buffer.from(input).toString('base64url')
export function createTokenClient({ accountId, clientId, certificateId, privateKeyPem, scope = ['rest_webservices'] }) { const host = accountId.replace(/_/g, '-').toLowerCase() const tokenUrl = `https://${host}.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token` let cached = null
function clientAssertion() { const now = Math.floor(Date.now() / 1000) const header = { alg: 'PS256', typ: 'JWT', kid: certificateId } const payload = { iss: clientId, scope, aud: tokenUrl, iat: now, exp: now + 3600 } const unsigned = `${b64url(JSON.stringify(header))}.${b64url(JSON.stringify(payload))}` const signature = crypto.sign('sha256', Buffer.from(unsigned), { key: privateKeyPem, padding: crypto.constants.RSA_PKCS1_PSS_PADDING, saltLength: 32, }) return `${unsigned}.${signature.toString('base64url')}` }
return async function getAccessToken() { if (cached && cached.expiresAt - 120_000 > Date.now()) return cached.token
const res = await fetch(tokenUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'client_credentials', client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', client_assertion: clientAssertion(), }), }) if (!res.ok) throw new Error(`Token request failed: ${res.status} ${await res.text()}`)
const body = await res.json() cached = { token: body.access_token, expiresAt: Date.now() + Number(body.expires_in) * 1000 } return cached.token }}Generate the key pair, then upload the public PEM in OAuth 2.0 Client Credentials (M2M) Setup:
openssl req -new -x509 -newkey rsa:4096 -sha256 -nodes \ -keyout private.pem -out public.pem -days 730 -subj "/CN=my-integration"kid is the certificate ID NetSuite shows after the upload. Add 'restlets' to scope if you call RESTlets. Full walkthrough: NetSuite OAuth 2.0 client credentials.