Skip to main content
View as Markdown

Getting Credentials via OAuth

Introduction

If you're an integrator building a platform or service that needs to access noon Partner APIs on behalf of multiple sellers, you can use the OAuth flow to programmatically create service accounts in your integrator project and grant them access to seller projects. This eliminates the need for sellers to manually create and share service account credentials.

This flow involves:

  • Your integrator service account credentials, which you use to authenticate your requests as the integrator, including the OAuth API endpoints described in this guide
  • Your OAuth client credentials (client_id and client_secret), which identify your OAuth application during the authorization code exchange

After the seller grants consent and you complete the exchange, noon returns a new service account credential in your integrator project with access to the seller's project. Use that returned credential for ongoing API calls you make on that seller's behalf.

What is OAuth?

OAuth 2.0 is an industry-standard authorization framework that enables applications to obtain delegated access to resources on behalf of a resource owner. If you're new to OAuth, we recommend reading the OAuth 2.0 overview or the official specification (RFC 6749) to understand the basic concepts before implementing the flow.

The OAuth flow allows your application to:

  • Obtain authorization from sellers to access their noon Partner account
  • Automatically create a service account in your integrator project
  • Grant that service account access to the seller's project
  • Receive the service account credentials directly in the token exchange response

Why Use OAuth?

OAuth is ideal for integrators who:

  • Manage multiple sellers - Automate credential management for many sellers at scale
  • Need centralized control - Manage all service accounts from your own integrator project
  • Want better security - Sellers never need to manually create or share credentials with you
  • Require programmatic access - Trigger service account creation via API without manual intervention

Prerequisites

  • You must be registered as a noon Partner Integrator
  • You already have your own integrator service account credentials and can authenticate requests as your integrator project. If you have not set this up yet, first follow Getting Your Credentials and Authenticating Your Requests.
  • You have requested and obtained OAuth client credentials (client_id and client_secret) from noon - contact noon to request these credentials. Store the secret when it is issued.
  • Your sellers must have a noon Partner account
OAuth API calls must be authenticated

The OAuth API endpoints in this guide are not anonymous endpoints. Your backend must call them using an authenticated noon session created from your integrator service account credentials.

The client_id and client_secret in the request body identify your OAuth application, but they do not replace the authenticated integrator session required to call noon APIs. Seller credentials are also not used here. Seller access is granted by the OAuth consent flow, and the seller-scoped service account credential is returned only after the token exchange completes.

How OAuth Flow Works

The OAuth flow for creating service accounts follows these steps:

Step 1: Authorization URL

Direct sellers to the noon authorization URL to grant your application access:

https://oauth.noon.partners/?
client_id=YOUR_CLIENT_ID
&state=RANDOM_STATE_STRING
&redirect_uri=YOUR_CALLBACK_URL
&code_challenge=CODE_CHALLENGE
&code_challenge_method=S256

Parameters:

  • client_id: Your OAuth client ID provided by noon
  • state: A random string to prevent CSRF attacks
  • redirect_uri: Optional. Which of your registered callback URLs to return the seller to. See Choosing a Callback URL
  • code_challenge: The PKCE challenge derived from a per-flow code_verifier you keep server-side. Required if your OAuth client is configured to require PKCE — see Securing the Flow with PKCE
  • code_challenge_method: Must be S256. Only SHA-256 is supported

Choosing a Callback URL

An OAuth client can register more than one callback URL — for example, separate URLs per environment. Name the one you want with redirect_uri:

  • Omit it and the seller is returned to the first URL registered on your client.
  • Send it and it must match one of your registered URLs exactly, including scheme, host, path and query. A mismatch is rejected rather than redirected, so the error stays on the consent screen instead of being sent to an unverified URL.

Adding or changing a registered callback URL is a change to your OAuth client — contact Support.

Step 2: Receive Authorization Code

After the seller grants permission, they will be redirected to your registered callback URL with an authorization code:

https://your-app.com/callback?code=AUTH_CODE&state=RANDOM_STATE_STRING&iss=https%3A%2F%2Foauth.noon.partners

Alongside code and state, the callback carries an iss parameter naming the authorization server that issued the code — https://oauth.noon.partners. This is RFC 9207 issuer identification, and it lets a client that talks to more than one authorization server detect a code being replayed from a different one.

If this is the only authorization server you integrate with, you can ignore it — but do not treat unexpected query parameters as an error: compare iss if you validate it, and ignore it otherwise.

Step 3: Exchange Code for Access Token

Use the authorization code to obtain an access token by calling the OAuth token endpoint:

Call this endpoint from your backend using the authenticated integrator session described in Authenticating Your Requests.

Endpoint: POST /identity/oauth/v1/token/create

Request:

{
"grant_type": "authorization_code",
"code": "AUTH_CODE",
"client_id": "YOUR_CLIENT_ID",
"client_secret": "YOUR_CLIENT_SECRET",
"code_verifier": "CODE_VERIFIER"
}

Send code_verifier only when the authorization URL for this flow carried a code_challenge, and send the verifier that matches that exact challenge. See Securing the Flow with PKCE.

Response:

{
"access_token": "eyJhbGc...",
"token_type": "TOKEN_TYPE_BEARER",
"expires_in": "3600s",
"scopes": ["access:grant"],
"project_code": "PRJ12345"
}

Step 4: Create Service Account and Receive Credentials

Exchange the access token to create a service account and receive its credentials:

Like the token creation call, this request must be sent through your authenticated integrator session.

Endpoint: POST /identity/oauth/v1/token/exchange

Request:

{
"access_token": "eyJhbGc..."
}

Response:

{
"status": {
"code": 0
},
"project_code": "PRJ12345",
"oauth_request_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"result": {
"key_id": "key-abc123",
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQ...",
"channel_identifier": "[email protected]",
"project_code": "PRJ12345",
"type": "apijwt",
"issued_at": "2026-04-20T12:00:00Z"
}
}

Response Fields:

  • status: Indicates whether the workflow executed successfully (code: 0 means success)
  • project_code: The seller's project code associated with this exchange
  • oauth_request_id: A unique identifier for this OAuth exchange request — use this to track the request (see Tracking OAuth Requests below)
  • result: The service account credentials — contains the private key and metadata needed to authenticate API calls. The schema matches the credential object returned by the API User Service CreateCredential endpoint. The channel_identifier on this object is the same value the API User Service accepts in place of user_code, so you can rotate or revoke this credential without needing to look up a user_code separately.
Store Your Credentials Securely

The result contains the private key, which is only returned once — noon does not store it. If you lose it, you will need to create a new credential via the API User Service. Store it in a secrets manager, never commit it to source control, and never log it.

Securing the Flow with PKCE

The authorization code is delivered to your callback through the seller's browser, so it passes through URL bars, browser history, referrer headers, and any proxy in between. PKCE (Proof Key for Code Exchange, RFC 7636) makes a leaked code useless on its own: the code becomes redeemable only by the application that started that specific flow.

You generate a random code_verifier per flow and keep it on your backend. You send only its SHA-256 hash — the code_challenge — on the authorization URL. The authorization server binds that challenge to the authorization code it issues, and at Step 3 it checks that the code_verifier you present hashes to the same value. Because SHA-256 cannot be reversed, anyone who intercepted the challenge or the code still cannot produce the verifier.

How to Implement It

  1. Before redirecting the seller, generate a code_verifier: a cryptographically random string, 43-128 characters long, using only the characters A-Z a-z 0-9 - . _ ~. Generating 32 random bytes and base64url-encoding them without padding produces a valid 43-character verifier.
  2. Derive the code_challenge as the base64url encoding, without padding, of the SHA-256 hash of the verifier.
  3. Store the verifier on your backend against the same session record where you keep state. It must never reach the browser.
  4. Add code_challenge and code_challenge_method=S256 to the authorization URL in Step 1.
  5. Send the matching code_verifier in the Step 3 token creation request.

Use a fresh verifier for every authorization flow and never reuse one.

PKCE Parameters

ParameterWhereDescription
code_challengeAuthorization URL (Step 1)Base64url, unpadded, of SHA-256(code_verifier)
code_challenge_methodAuthorization URL (Step 1)Must be S256. plain is not supported
code_verifierToken creation body (Step 3)The original random string, 43-128 characters from A-Z a-z 0-9 - . _ ~

When PKCE Is Required

PKCE is enabled per OAuth client, and your client's configuration is the only thing that decides whether it is mandatory — removing code_challenge from the authorization URL does not opt a configured client out.

Your OAuth clientWhat is expected
Configured to require PKCEEvery flow must carry a code_challenge, and every token creation call must carry the matching code_verifier. Requests without them are rejected
Not configured to require PKCEPKCE is optional per flow. If a flow sends a code_challenge, that flow must send the matching code_verifier. If it does not, the token creation call must omit code_verifier entirely

Existing integrations that predate PKCE keep working unchanged until the requirement is enabled on your client.

Adopt PKCE before it is required

Implement PKCE first, confirm your flows work end to end, then contact Support to have the requirement enabled on your OAuth client. PKCE is expected to become mandatory for all OAuth clients over time, so integrations that adopt it early will not need changes later.

Security Considerations

Important
  • Never expose your client_secret in client-side code or public repositories
  • Store your client_secret when it is issued. If it is lost or you suspect it leaked, contact Support to have it rotated
  • Validate the state parameter to prevent CSRF attacks
  • Use PKCE so an intercepted authorization code cannot be redeemed without your code_verifier
  • Keep the code_verifier on your backend - it must never be sent to the browser or included in the authorization URL
  • Store access tokens securely and never log them
  • Use HTTPS for all OAuth communications
  • Access tokens are single-use - exchange them immediately for service account creation

Token Lifecycle

  • Access Token Lifetime: 1 hour (single use)
  • Authorization Code Lifetime: 10 minutes (single use)

Error Handling

Common error scenarios:

ErrorDescriptionSolution
Invalid or expired authorization codeAuthorization code has expired (10 min) or already been usedRequest new authorization from seller
Invalid client_idOAuth client ID not foundVerify your client_id
redirect_uri does not match any registered redirect URI for this clientThe redirect_uri on the authorization URL is not one of your registered callback URLsSend a registered URL exactly as registered, or omit the parameter to use the first one. See Choosing a Callback URL
Invalid client_secretClient secret does not matchVerify your client_secret
Invalid, expired, or already used access tokenAccess token is invalid, expired, or has already been consumedRestart the OAuth flow to get a new access token
code_verifier is required: the authorization request used PKCEThe flow started with a code_challenge, but the token creation call did not send a code_verifierSend the code_verifier you stored for this flow. See Securing the Flow with PKCE
Invalid code_verifierThe code_verifier does not hash to the code_challenge bound to this authorization codeSend the verifier belonging to this flow. A mismatch usually means verifiers were mixed up between concurrent flows or regenerated after the redirect. The code is consumed by the failed attempt, so restart from Step 1
code_verifier provided but the authorization request did not use PKCEA code_verifier was sent for a flow whose authorization URL carried no code_challengeEither send code_challenge on the authorization URL, or omit code_verifier from the token creation call. Do not mix the two
This client requires PKCE: the authorization request carried no code_challengeYour OAuth client requires PKCE, but this authorization code was issued for a flow without a code_challengeRestart from Step 1 with code_challenge and code_challenge_method=S256 on the authorization URL
code_verifier must be 43-128 characters long and use only [A-Za-z0-9-._~]The code_verifier does not meet the RFC 7636 formatGenerate the verifier as described in Securing the Flow with PKCE — base64url encoding without padding, no +, /, or = characters
User is not activeThe target service account is currently deactivated, so credentials cannot be generatedReactivate the service account from the API Users page, then restart the OAuth flow from Step 1 to get a fresh authorization code and access token
apijwt active key quota exceeded for the accountThe service account behind this OAuth grant already has the maximum number of active keys (default: 5), so the token exchange cannot mint another oneRevoke an existing key on that service account, then restart the OAuth flow. See Recovering from a Key Quota Exceeded Error below
Non-successful response from token exchangeThe ExchangeToken call returned a non-success status (e.g. timeout, or other unexpected failure)Restart the OAuth flow from Step 1 to obtain a new authorization code and access token. Since access tokens are single-use, the original token cannot be retried

Some PKCE problems are caught before any authorization code exists, so the seller sees them on the consent screen instead of your backend receiving an API error. No code is issued, and the seller cannot complete the flow until you fix the authorization URL.

ErrorCause
This client requires PKCE: code_challenge is missingYour OAuth client requires PKCE, but the authorization URL had no code_challenge
code_challenge must be 43-128 characters long and use only [A-Za-z0-9-._~]The challenge is not base64url-encoded without padding, or is the wrong length
Unsupported code_challenge_method: plain. Supported: S256code_challenge_method was set to something other than S256
code_challenge_method requires code_challengecode_challenge_method was sent without a code_challenge

If a seller reports being unable to complete consent, check the authorization URL your application generated before investigating further.

Recovering from a Key Quota Exceeded Error

Each service account can have at most 5 active keys. Because the OAuth token exchange always tries to mint a new key on the seller's service account, repeatedly re-running OAuth for the same seller — for example, after losing a previously issued private key — will eventually hit apijwt active key quota exceeded for the account.

The fix is to free up a key slot on that service account before re-running the exchange. Use the API User Service to do this. You don't need a user_code — the channel_identifier you received from a prior token exchange result works as the account identifier (see Identifying the Target Service Account).

  1. Pick what to revoke.
    • If you still have a previously issued key_id that you no longer need, revoke just that key with RemoveCredentials and a specific key_id.
    • If you've lost track of all prior keys for this service account, call RemoveCredentials without a key_id to deactivate every active key on the account at once. Any application still authenticating with one of those keys will start failing immediately, so only do this when you are sure none of the existing keys are in use.
  2. Re-run the OAuth flow. Because access tokens are single-use, you'll need a fresh authorization code from the seller and a new access token before retrying Step 4.
  3. Store the new credential. Treat the new result.private_key as you would any other — it is only returned once.
Prefer revoking a specific key when you can

Removing all keys is a blunt instrument. If you have any working key for the account, revoke that specific key_id and let other live credentials (e.g. ones a seller-side automation is still using) keep working.

Code Examples

See the OAuth Quickstart Guide for complete code examples in multiple languages showing how to implement the OAuth flow.

Tracking OAuth Requests

Every token exchange returns an oauth_request_id that you can use to monitor the progress of the service account creation workflow. This is especially useful when managing OAuth integrations at scale across multiple sellers.

To track request status:

  1. Log in to the noon Partners Access App
  2. Navigate to the OAuth tab in your integrator project
  3. You will see a list of all OAuth requests initiated for your OAuth clients in the past 24-48 hours.
  4. Use the oauth_request_id to find and trace a specific request

Each request progresses through the following statuses:

StatusDescription
requestedThe seller initiated the OAuth authorization flow
grantedThe seller approved the consent screen
processingThe authorization code was exchanged for an access token
executingThe token was consumed and the service account creation workflow is running
completedThe workflow finished successfully and the service account is ready
tip

Store the oauth_request_id from the ExchangeToken response in your system. If a seller reports issues with their integration setup, you can use this ID to quickly look up the request status and diagnose any problems.

Next Steps