Skip to navigation

O Auth Token

View as Markdown

Exchange a credential for an access token.

Available to: Registered OAuth client applications and NT Connect partners

Environments: Demo, Live. The jwt-bearer grant is Live in practice, because partner configurations are provisioned there.

Rate Limit: 10 requests per hour, 30-second back-off, counts failed requests only. OAuth errors are returned as HTTP 200 and are not failures for this purpose, so only transport-level failures count toward the penalty.

Select a grant with grant_type; which of the other request fields apply depends on the grant you choose.

grant_typeUse it toRequired fields
authorization_codeRedeem a code from the authorize endpointcode, redirect_uri
refresh_tokenRenew an access token without re-authenticatingrefresh_token
urn:ietf:params:oauth:grant-type:jwt-bearerExchange a signed partner assertion for a token on behalf of one of your usersassertion
client_credentialsAuthenticate a headless client that acts as its own service account, with no user present. The response carries no refresh token; re-authenticate when the access token expires.client_id, client_secret

Authenticate the client with client_id and client_secret in the body, or with httpAuth (base64 client_id:client_secret). Public clients use PKCE and send code_verifier instead of a secret. For the authorization-code flow, see the OAuth JavaScript tutorial.

Warning: This endpoint returns HTTP 200 for successes and errors. Always check for an error field in the response body to determine whether the request succeeded or failed.

Partner SSO: the jwt-bearer Grant

NT Connect partners exchange a short-lived JWT, signed with their registered key, for a NinjaTrader access token scoped to one of their users. No user password is involved and no NinjaTrader login prompt is shown.

Assertion Requirements

The assertion must be signed with RS256 and carry a kid header identifying the signing key. Required claims:

ClaimValue
issThe issuer registered on your partner configuration. It must match exactly.
subThe numeric NinjaTrader user ID of the user you are acting for. Users are never auto-provisioned; the account must already exist and belong to your organization.
audThe audience registered on your partner configuration (in practice the token endpoint URL of the environment you are calling). It must match exactly.
iatIssued-at time.
expExpiry. exp minus iat must not exceed 300 seconds; 60 seconds is recommended.
jtiA unique identifier. Reusing one is rejected as a replay.

Clock skew of up to 60 seconds is tolerated on the time claims. Any additional claims you include are ignored.

Signing Keys

NinjaTrader fetches your public keys from the JWKS URL on your partner configuration and caches them for one hour. A key rotation is picked up automatically the first time an assertion arrives with a kid that is not in the cache, so publish the new key before you start signing with it.

Sample Call

curl -X POST 'https://live.tradovateapi.com/v1/auth/oauthtoken' \
-H 'Content-Type: application/json' \
-d '{
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"assertion": "<your-signed-jwt>"
}'
{
"access_token": "…",
"refresh_token": "…",
"token_type": "bearer",
"expires_in": 86400,
"refresh_token_expires_in": 93600
}
Read the token lifetimes from expires_in and refresh_token_expires_in rather than hard-coding them. They are environment configuration, and there is no partner-specific override. An id_token is only issued on the authorization_code grant; it is always null for jwt-bearer.

Scopes

The resulting token carries the scopes configured on your partner client application, intersected with the scopes the user has granted. A user who has revoked your application is rejected with access_denied.

Refresh Token Behavior

Refresh tokens are single-use and rotate: each refresh consumes the current token and returns a new one. Because a partner session is keyed on the partner and the user rather than on a device, a new jwt-bearer exchange replaces the refresh token issued by the previous exchange for that same user. Keep the most recent token pair, or re-run the exchange, rather than holding several in parallel.

Signing a User Into a NinjaTrader-Hosted Page

To hand a signed-in user off to a NinjaTrader-hosted page, use the partner access token from this endpoint to mint a short-lived code with shortGrantCode, then redirect the user’s browser with that code attached. The access token itself never leaves your backend. The NinjaTrader application redeems the code with exchangeShortGrantCode.

Common Failure Scenarios

  • The assertion is signed with an algorithm other than RS256, or omits the kid header.
  • iss or aud does not exactly match the values registered on the partner configuration.
  • The assertion lifetime exceeds 300 seconds.
  • The same jti was already used.
  • sub does not resolve to an active user in your organization.
  • The partner configuration is disabled or archived.
  • assertion is missing on a jwt-bearer call, which matches no grant shape and returns bad_request.

Error Messages

errorerror_descriptionTrigger
invalid_clientUnknown issuer: <iss>No partner configuration matches the assertion’s iss
invalid_clientProvider is disabled: <partner> / Provider is archived: <partner>The partner configuration is not currently usable
invalid_clientPartner SSO client application is not configuredThe partner’s client application is missing or not authorized for this flow
invalid_grantInvalid assertion: …Expired assertion, bad signature, audience mismatch, a missing kid, sub, iat, exp, or jti, or a lifetime over the 300-second cap
invalid_grantAssertion jti has already been usedReplayed assertion
invalid_grantUser not found: userId=<id>sub is a valid user ID but no such user exists. This is the usual shape.
invalid_grantUser not found: sub=<sub>sub is not a positive integer, so it never resolved to a user ID
invalid_grantUser account is not active: <userId>The user account is inactive
invalid_grantThe user is not in your partner organizationThe user belongs to a different organization. The message also reports the organization IDs involved; treat that detail as diagnostic rather than a stable format.
access_deniedUser has denied this applicationThe user revoked your application
unsupported_grant_typeSupported: authorization_code, refresh_token, client_credentials, urn:ietf:params:oauth:grant-type:jwt-bearerAn unrecognized grant_type from a public client. Confidential clients get bad_request instead.
bad_requestInvalid requestThe request shape matched no supported grant, including an unrecognized grant_type sent with a client secret
server_errorInternal error: …Unexpected server-side failure. The detail relays the underlying error text; do not parse it.

Request

This endpoint expects an object.
grant_typestringRequired<=64 characters
codestringOptional<=8192 characters
redirect_uristringOptional<=8192 characters
client_idstringOptional<=8192 characters
client_secretstringOptional<=8192 characters
httpAuthstringOptional<=8192 characters
refresh_tokenstringOptional<=8192 characters
code_verifierstringOptional<=8192 characters
resourcestringOptional<=8192 characters
assertionstringOptional<=8192 characters

Response

OAuthTokenResponse
access_tokenstringOptional<=8192 characters
refresh_tokenstringOptional<=8192 characters
token_typestringOptional<=64 characters
expires_inintegerOptional
refresh_token_expires_inintegerOptional
errorstringOptional<=64 characters
error_descriptionstringOptional<=8192 characters
id_tokenstringOptional<=8192 characters