# Authenticating NetSuite RESTlets with OAuth 2.0 and Token-Based Authentication

> Source: https://netray.co/erp-help/netsuite-restlet-oauth2-token-based-authentication
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: ERP Help

## Short answer

NetSuite RESTlets can be called with either Token-Based Authentication (TBA, OAuth 1.0a signed requests) or OAuth 2.0, and both require a Setup > Integrations > Manage Integrations record before any token is issued. Machine-to-machine OAuth 2.0 uses a client credentials grant with a JWT bearer assertion signed by a certificate; TBA uses a consumer key/secret plus a per-user access token signed with HMAC-SHA256.

## Kind

advanced

## System

netsuite

## Erp

Oracle NetSuite

## Module

Integrations / RESTlets

## Query

how to authenticate a NetSuite RESTlet with OAuth 2.0

## Alternate Queries

- netsuite token based authentication TBA setup
- netsuite restlet 401 invalid login attempt
- netsuite oauth 2.0 client credentials grant setup
- netsuite integration record vs access token

## Applies To

SuiteScript 2.x RESTlets, all NetSuite editions with SuiteCloud and Token-Based Authentication or OAuth 2.0 features enabled

## Steps

### Wire up authenticated RESTlet access

**Items:**

Enable the features at Setup > Company > Enable Features > SuiteCloud: turn on 'Token-Based Authentication' for TBA, or 'OAuth 2.0' for the client credentials / authorization code flows.

Create an Integration record at Setup > Integrations > Manage Integrations > New, give it a name, and check the authentication method(s) you plan to use (TBA and/or OAuth 2.0). Note the generated Consumer Key/Secret (TBA) or Client ID/Secret (OAuth 2.0) shown only once.

For OAuth 2.0 machine-to-machine access, generate an RSA key pair, upload the public key/certificate to the Integration record under the OAuth 2.0 section, and keep the private key to sign JWT assertions.

For TBA, go to Setup > Users/Roles > Access Tokens > New, pick the application (the Integration record), the user, and a role that has the 'REST Web Services' and 'SuiteScript' permissions; save the generated Token ID and Token Secret immediately.

For OAuth 2.0, POST a signed JWT assertion to https://ACCOUNTID.suitetalk.api.netsuite.com/services/rest/auth/oauth2/v1/token with grant_type=client_credentials to receive a short-lived bearer access token.

For TBA, sign each RESTlet request with an OAuth 1.0a Authorization header containing oauth_consumer_key, oauth_token, oauth_signature_method=HMAC-SHA256, oauth_timestamp, oauth_nonce and oauth_signature, using the realm as the account ID (with an underscore for sandbox, e.g. 123456_SB1).

Confirm the role used has the 'REST Web Services' permission under Setup at minimum, plus record-level permissions for whatever the RESTlet touches; a missing permission surfaces as INSUFFICIENT_PERMISSION rather than an authentication failure.

Call the RESTlet URL from Customization > Scripting > Script Deployments (copy the External URL), passing the bearer token or TBA Authorization header instead of session cookies.

## Sections

### OAuth 2.0 versus Token-Based Authentication

**Body:**

TBA (OAuth 1.0a) has been NetSuite's long-standing machine integration method: a consumer key/secret pair tied to the Integration record, plus a per-user access token, all used to compute an HMAC-SHA256 signature on every request. It requires no token refresh flow because tokens do not expire on their own, only when revoked.

OAuth 2.0 adds a standards-based alternative with two relevant flows for server-to-server integrations: the client credentials grant (a JWT bearer assertion signed with an RSA private key, exchanged for a short-lived access token) and the authorization code grant for user-interactive apps. OAuth 2.0 access tokens expire (commonly around an hour) and must be refreshed, which is the tradeoff for not having to compute a per-request signature.

New integrations are generally steered toward OAuth 2.0 where the client supports it, but TBA remains fully supported and is often simpler for a single trusted server-side integration that does not need token refresh logic.

### Diagnosing 401 Invalid Login Attempt

**Body:**

The most common TBA cause is clock skew: oauth_timestamp must be within a small tolerance of NetSuite's server time, so a server with drifted system clock will fail every request with a generic invalid login error that gives no hint it is a timestamp problem.

The second most common cause is the realm: it must be the exact account ID as NetSuite expects it, including the underscore-separated sandbox suffix (123456_SB1, not 123456-sb1 or lowercase). A mismatched realm authenticates against the wrong account context and fails even with correct keys.

Also check that Token-Based Authentication (or OAuth 2.0) is still enabled at the account level, that the access token has not been revoked at Setup > Users/Roles > Access Tokens, and that the role assigned to the token still has the 'REST Web Services' permission; permission changes on the role do not require reissuing the token but do take effect immediately.

### Common OAuth 2.0 setup mistakes

**Body:**

Uploading the wrong key format to the Integration record (NetSuite expects a specific certificate/public key format) causes the JWT signature verification to fail silently with a generic invalid_client error rather than a descriptive message about the key.

Requesting a scope the Integration record was not granted (for example rest_webservices without the RESTlets checkbox enabled on the Integration record) returns an insufficient_scope error at the RESTlet call even though the token exchange itself succeeded.

Forgetting that the OAuth 2.0 access token is short-lived and hard-coding it in a script or scheduled job breaks the integration a short time later; production integrations need to refresh the token before each burst of calls or on a 401.

## Pitfalls

- Using the production account ID as the realm when calling a sandbox RESTlet, or vice versa.
- Reissuing an Integration record's Consumer Secret (which invalidates all existing TBA tokens issued under it) without warning downstream integrations.
- Granting the role 'Full Access' broadly instead of the specific permissions the RESTlet needs, which passes security review poorly for machine accounts.
- Not handling OAuth 2.0 token expiry, resulting in intermittent 401s that look like a NetSuite outage rather than an expired token.
- Testing authentication from Postman successfully but failing in code because the OAuth 1.0a signature base string construction (parameter ordering, percent-encoding) differs subtly from the library used in Postman.

## Ai Angle

When a partner or customer reports RESTlet 401s, ERPray can walk through the Integration record, the role's permissions and the token status in one grounded pass and point at the specific mismatch (revoked token, wrong realm, expired OAuth 2.0 token) instead of a support ticket that starts from scratch each time. For teams standing up new integrations, SyteRay-style scaffolding can generate the signed-request boilerplate for whichever auth method the target system already uses.

## Faq

### Do I need a separate Integration record for TBA and OAuth 2.0?

**Answer:** No, a single Integration record can have both authentication methods checked. What differs is how you use it afterward: TBA needs an Access Token record per user/role, OAuth 2.0 needs a certificate uploaded for client credentials or a redirect URI for authorization code flow.

### How long do NetSuite OAuth 2.0 access tokens last?

**Answer:** Access tokens are short-lived, typically on the order of an hour, and must be refreshed by requesting a new token with the client credentials or refresh token flow before it expires; there is no indefinite session like a browser login.

### Can I call a RESTlet with a plain NetSuite user session cookie instead?

**Answer:** Only from within an authenticated browser session, which is not viable for server-to-server integrations. Programmatic access should always use TBA or OAuth 2.0 so the integration has its own auditable identity separate from a human user's login session.

### Why does the RESTlet work in the sandbox but fail in production with the same code?

**Answer:** Each account (production and each sandbox) has its own Integration record IDs, consumer keys and access tokens, and its own realm string. Code that hard-codes sandbox credentials or the sandbox realm will fail in production until the production-specific values are substituted.

## Search terms

netsuite restlet oauth 2.0, netsuite token based authentication setup, netsuite TBA access token, netsuite 401 invalid login attempt, netsuite integration record consumer key, netsuite oauth 2.0 client credentials, netsuite restlet authorization header, netsuite REST_WEBSERVICES permission, netsuite jwt bearer assertion

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
