← All posts
IntegrationRESTletAuthenticationTBAOAuth 2.0Debugging

Debugging NetSuite RESTlet Auth Errors: INVALID_LOGIN_ATTEMPT, TBA, and OAuth

Ryzoa··6 min read

Debugging NetSuite RESTlet Auth Errors: INVALID_LOGIN_ATTEMPT, TBA, and OAuth

NetSuite authentication errors tend to show up as nothing. The calling system gets an empty response. NetSuite's execution log has no entry, because authentication failed before the script ran.

The errors covered here are INVALID_LOGIN_ATTEMPT (TBA/RESTlet calls), invalid_grant (OAuth 2.0), missing role permissions, and RESTlet scope problems. Related: the TBA to OAuth 2.0 migration guide and the silent failure diagnosis post.

RESTlets use TBA; REST Web Services use OAuth 2.0

RESTlets (script type restlet, URL format /app/site/hosting/restlet.nl) authenticate external calls using Token-Based Authentication: a consumer key, consumer secret, token ID, and token secret signed per-request using HMAC-SHA256 (OAuth 1.0a). OAuth 2.0 is not supported for external-to-RESTlet calls.

REST Web Services (/services/rest/record/v1/...) use OAuth 2.0 bearer tokens. TBA is not used here.

If you are seeing INVALID_LOGIN_ATTEMPT, you are calling a RESTlet with TBA credentials. If you are seeing invalid_grant, you are using OAuth 2.0 against REST Web Services.

INVALID_LOGIN_ATTEMPT

This error appears in the HTTP response body when a RESTlet call fails at the authentication layer. The script never runs; the execution log has no entry for the call.

Cause 1: Token pair revoked

Go to Setup > Users/Roles > Access Tokens. Find the token associated with your integration. If it is not there, it has been deleted. Common triggers:

  • A user's role was changed or removed. Access tokens are tied to a user-role pair; when the role association changes, the token is invalidated.
  • An administrator rotated credentials manually.
  • The Integration Record was edited or re-saved, which can invalidate existing tokens in some account configurations.

Generate a new token in the Access Tokens list using the same Integration Record and role. Update the credentials in your calling system.

Cause 2: Wrong consumer key or secret

Integration credentials are shown once when the Integration Record is saved. If those values were not stored correctly, the consumer key or secret in your calling system is wrong.

Go to Setup > Integration > Manage Integrations and open the relevant Integration Record. You cannot view the existing credentials, but you can re-save the record to generate new ones. Update your calling system with the new values.

Cause 3: IP address restriction

Integration Records have an optional "Allowed IPs" field. If your calling server's IP is not in the list, authentication fails with INVALID_LOGIN_ATTEMPT even if the credentials are correct.

Check the Integration Record at Setup > Integration > Manage Integrations. If the field is populated and your server IP is not in it, add it or remove the restriction.

Cause 4: Script deployment not accepting external calls

Each RESTlet deployment has an "External Access" setting. If this is disabled, external calls fail at authentication rather than returning a useful script-level error.

Go to Customization > Scripting > Scripts, open the RESTlet, and check its deployments. The deployment status must be "Released" and the external access flag must be enabled.

Cause 5: Missing "Log in using Access Tokens" permission

The role assigned to the token must have the "Log in using Access Tokens" permission under Setup > Permissions > Setup. Without it, TBA authentication fails regardless of whether the token is valid.

Open the role at Setup > Users/Roles > Manage Roles, go to the Permissions tab, and check the Setup subtab.

invalid_grant (OAuth 2.0)

This error appears in OAuth 2.0 token responses from REST Web Services. It means the token is no longer valid.

Authorization Code flow

The authorization code itself expires after a short window (typically 10 minutes). Once exchanged, the resulting access token expires after 60 minutes. The refresh token expires after 7 days.

If you see invalid_grant on a refresh request, the 7-day window has passed and the user needs to reauthorise. Design your integration to detect this and prompt reauthorisation rather than silently failing.

Client Credentials flow

Client Credentials tokens do not use refresh tokens. A new token is requested directly for each session using a signed JWT assertion. invalid_grant here usually means:

  • The Integration Record was disabled or the client credentials grant was unchecked.
  • The certificate uploaded to NetSuite has expired or been replaced, so the JWT assertion can no longer be verified.
  • The private key used to sign the assertion does not match the public key on record.

Re-upload the certificate at Setup > Integration > OAuth 2.0 Client Credentials (Machine to Machine) Setup and generate a new token.

Missing role permissions

Even when authentication succeeds, the role assigned to the token may not have the permissions the script needs to run. The result is a 403, or a script-level error in the execution log.

Check the execution log at Customization > Scripting > Script Execution Logs. A permission error at the script level will appear here even if the call completes the authentication stage.

Common gaps:

  • The role lacks read or write access to the record types the script accesses. Check Transactions, Lists, and Reports permission tabs in the role.
  • The role cannot access the subsidiary or department involved in the transaction.
  • The role does not have SuiteScript permission (Setup > Permissions > Setup > SuiteScript).

The minimum permissions for an integration role: Log in using Access Tokens, SuiteScript, and whichever record-level access the script needs. Do not use an admin role for integrations.

RESTlet scope issues

These aren't authentication errors, but they look like one from outside: the integration stops working, and neither side produces a clear error.

Wrong URL format

A RESTlet URL looks like:

https://[account-id].restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=[script-id]&deploy=[deploy-id]

The script parameter takes the internal ID of the script record, not the script file name. The deploy parameter takes the deployment internal ID. Verify both in Customization > Scripting > Scripts.

Using the script file name or an incorrect deploy ID produces a 404 or a malformed response, which can look like an auth error to the calling system.

Deployment not released

A deployment in "Testing" status is only accessible to logged-in users. External calls require status "Released". Check the deployment record and change the status if needed.

GET versus POST mismatch

RESTlets define separate handler functions for GET, POST, PUT, and DELETE. Calling with the wrong HTTP method produces an error at the script level, not the auth level, but it is easy to misread in the calling system's logs. Confirm that your calling system's HTTP method matches the function the RESTlet exposes.

Tracing authentication failures in practice

Authentication failures at the TBA layer produce no execution log entry. The SuiteCloud Inspector (if available on your account tier) gives the most detail. Otherwise, add explicit logging in the integration itself.

On the calling side, log the full HTTP response: status code, headers, and body. A TBA auth failure returns a JSON body with "type": "error.type.invalidcredentials" or similar. This is more useful than the generic "connection refused" message some middleware platforms surface.

If the failure is intermittent, check whether it correlates with role changes, admin maintenance windows, or IP address changes on the calling server. Intermittent INVALID_LOGIN_ATTEMPT errors that clear on their own usually mean credentials were temporarily rotated and the integration eventually picked up the new values. The window when it fails can still cause data gaps, though.

The silent failure diagnosis post covers how to build alerting around authentication failures so they do not produce undetected data gaps.


If an integration is producing auth errors you cannot diagnose from this list, book a technical review. Bring the HTTP response body and the execution log if there is one. It also helps to know what changed around the time it started failing.

Have a specific problem in mind?

A 30-minute technical review call to understand what's in your codebase and whether this is the right fit.

Book a technical review