NetSuite OAuth 2.0 M2M — Key Points
- Machine-to-Machine (M2M) OAuth 2.0 replaces TBA for server-to-server integrations as of NetSuite 2023.1.
- Uses certificate-based JWT assertion — no user credentials in the request at all.
- Scopes are declared at the integration record level, not per-token.
- Access tokens expire in 60 minutes; your integration must handle refresh automatically.
NetSuite’s OAuth 2.0 Machine-to-Machine (M2M) flow lets server-side integrations authenticate without any user interaction. Instead of a user logging in and granting access, the integration presents a signed JSON Web Token (JWT) to prove its identity. NetSuite verifies the signature against a certificate you register upfront, then issues an access token. This guide walks through the full setup with Postman examples.
How M2M Authentication Works
Your Integration Server NetSuite
────────────────────── ─────────
1. Build JWT claim set:
iss = Client ID
sub = Client ID
aud = token endpoint URL
iat = now (Unix timestamp)
exp = now + 60 seconds
2. Sign JWT with private key
(RS256 algorithm)
│
│ POST /services/rest/auth/oauth2/v1/token
│ grant_type=client_credentials
│ client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
│ client_assertion=[signed JWT]
▼
3. Verify JWT signature
against registered cert
4. Issue access token
(valid 60 minutes)
◄─────────── access_token ────────────
5. Call REST API with:
Authorization: Bearer [access_token]
Step 1: Create the Integration Record in NetSuite
In NetSuite, navigate to Setup > Integration > Manage Integrations > New.
Give it a descriptive name like “WooCommerce Sync M2M”. This appears in audit logs.
Check “Client Credentials (Machine to Machine)” under the Authentication section. Do not check “Authorization Code Grant” for server-to-server integrations.
Select the REST Web Services scope at minimum. Add SuiteAnalytics if you need SuiteQL access. Narrower scopes = less blast radius if credentials are compromised.
The Client ID is shown after saving. This goes into your JWT as both the iss and sub claims. The Client Secret is NOT used in M2M — do not store it.
Step 2: Generate and Register a Certificate
# Generate 2048-bit RSA private key
openssl genrsa -out netsuite_m2m_private.pem 2048
# Generate self-signed certificate (valid 2 years)
openssl req -new -x509 -key netsuite_m2m_private.pem
-out netsuite_m2m_cert.pem -days 730
-subj "/CN=MyIntegration/O=MyCompany"
# Verify the certificate
openssl x509 -in netsuite_m2m_cert.pem -text -noout
Upload netsuite_m2m_cert.pem to the integration record (Setup > Integration > Manage Integrations > [your integration] > Client Credentials tab > Upload Certificate). Store netsuite_m2m_private.pem securely — this is your credential.
Private key storage rules:
Never commit the private key to source control. Use a secrets manager (AWS Secrets Manager, HashiCorp Vault, or at minimum an environment variable). Rotate the certificate before the expiry date — set a calendar reminder for 60 days before.
Step 3: Build the JWT and Get a Token (Postman)
{
"iss": "your-client-id-from-integration-record",
"sub": "your-client-id-from-integration-record",
"aud": "https://[accountid].suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token",
"iat": 1720000000,
"exp": 1720000060
}
In Postman, use the Pre-request Script tab to build and sign the JWT, then POST to the token endpoint with grant_type=client_credentials and client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer.
| JWT Claim | Value | Notes |
|---|---|---|
| iss | Client ID from integration record | Issuer — identifies your application |
| sub | Client ID (same as iss) | Subject — same value for M2M |
| aud | NetSuite token endpoint URL | Must include account ID in domain |
| iat | Current Unix timestamp | Issued at — must be within 5 min of NetSuite server time |
| exp | iat + 60 seconds | JWT expiry — max 60 seconds, not the access token expiry |
Step 4: Use the Access Token
The token endpoint returns a JSON object with access_token and expires_in (3600 seconds = 60 minutes). Add the token to every REST API call:
GET https://[accountid].suitetalk.api.netsuite.com/services/rest/record/v1/salesOrder/12345 Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... Content-Type: application/json
Cache the access token until 5 minutes before expiry:
Do not request a new access token on every API call. Cache it in memory and track the expiry time. Request a new token when the cached one has less than 5 minutes remaining. This avoids unnecessary token endpoint calls and keeps your integration within rate limits.
References
- NetSuite OAuth 2.0 Client Credentials FlowOracle NetSuite Help — official documentation for M2M authentication setup and JWT structure.
- RFC 7523 — JWT Profile for OAuth 2.0 Client AuthenticationIETF — the specification that defines the JWT bearer assertion grant type used by NetSuite M2M.
- RFC 7519 — JSON Web Token (JWT)IETF — the base JWT specification defining claims structure and signing.
- NetSuite REST Web Services OverviewOracle NetSuite Help — REST API reference for using access tokens after authentication.
Frequently asked questions
How does NetSuite M2M authentication work?
You register an integration record, upload a certificate, then exchange a signed JWT for a short-lived access token used on API calls.
Do I need a certificate?
Yes. M2M uses certificate-based client credentials rather than a user password, and the certificate must be registered against the integration record.
Can I test it before writing any code?
Yes. The guide includes a Postman flow that returns a working token, so you can confirm the setup before building anything.

Leave a Reply