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_idandclient_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.
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
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 noonstate: A random string to prevent CSRF attacksredirect_uri: Optional. Which of your registered callback URLs to return the seller to. See Choosing a Callback URLcode_challenge: The PKCE challenge derived from a per-flowcode_verifieryou keep server-side. Required if your OAuth client is configured to require PKCE — see Securing the Flow with PKCEcode_challenge_method: Must beS256. 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: 0means success)project_code: The seller's project code associated with this exchangeoauth_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. Thechannel_identifieron this object is the same value the API User Service accepts in place ofuser_code, so you can rotate or revoke this credential without needing to look up auser_codeseparately.
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
- Before redirecting the seller, generate a
code_verifier: a cryptographically random string, 43-128 characters long, using only the charactersA-Z a-z 0-9 - . _ ~. Generating 32 random bytes and base64url-encoding them without padding produces a valid 43-character verifier. - Derive the
code_challengeas the base64url encoding, without padding, of the SHA-256 hash of the verifier. - Store the verifier on your backend against the same session record where you keep
state. It must never reach the browser. - Add
code_challengeandcode_challenge_method=S256to the authorization URL in Step 1. - Send the matching
code_verifierin the Step 3 token creation request.
Use a fresh verifier for every authorization flow and never reuse one.
PKCE Parameters
| Parameter | Where | Description |
|---|---|---|
code_challenge | Authorization URL (Step 1) | Base64url, unpadded, of SHA-256(code_verifier) |
code_challenge_method | Authorization URL (Step 1) | Must be S256. plain is not supported |
code_verifier | Token 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 client | What is expected |
|---|---|
| Configured to require PKCE | Every 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 PKCE | PKCE 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.
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
- 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:
| Error | Description | Solution |
|---|---|---|
Invalid or expired authorization code | Authorization code has expired (10 min) or already been used | Request new authorization from seller |
Invalid client_id | OAuth client ID not found | Verify your client_id |
redirect_uri does not match any registered redirect URI for this client | The redirect_uri on the authorization URL is not one of your registered callback URLs | Send a registered URL exactly as registered, or omit the parameter to use the first one. See Choosing a Callback URL |
Invalid client_secret | Client secret does not match | Verify your client_secret |
Invalid, expired, or already used access token | Access token is invalid, expired, or has already been consumed | Restart the OAuth flow to get a new access token |
code_verifier is required: the authorization request used PKCE | The flow started with a code_challenge, but the token creation call did not send a code_verifier | Send the code_verifier you stored for this flow. See Securing the Flow with PKCE |
Invalid code_verifier | The code_verifier does not hash to the code_challenge bound to this authorization code | Send 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 PKCE | A code_verifier was sent for a flow whose authorization URL carried no code_challenge | Either 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_challenge | Your OAuth client requires PKCE, but this authorization code was issued for a flow without a code_challenge | Restart 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 format | Generate the verifier as described in Securing the Flow with PKCE — base64url encoding without padding, no +, /, or = characters |
User is not active | The target service account is currently deactivated, so credentials cannot be generated | Reactivate 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 account | The service account behind this OAuth grant already has the maximum number of active keys (default: 5), so the token exchange cannot mint another one | Revoke 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 exchange | The 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 |
PKCE Errors on the Consent Screen
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.
| Error | Cause |
|---|---|
This client requires PKCE: code_challenge is missing | Your 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: S256 | code_challenge_method was set to something other than S256 |
code_challenge_method requires code_challenge | code_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).
- Pick what to revoke.
- If you still have a previously issued
key_idthat you no longer need, revoke just that key with RemoveCredentials and a specifickey_id. - If you've lost track of all prior keys for this service account, call RemoveCredentials without a
key_idto 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.
- If you still have a previously issued
- 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.
- Store the new credential. Treat the new
result.private_keyas you would any other — it is only returned once.
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:
- Log in to the noon Partners Access App
- Navigate to the OAuth tab in your integrator project
- You will see a list of all OAuth requests initiated for your OAuth clients in the past 24-48 hours.
- Use the
oauth_request_idto find and trace a specific request
Each request progresses through the following statuses:
| Status | Description |
|---|---|
requested | The seller initiated the OAuth authorization flow |
granted | The seller approved the consent screen |
processing | The authorization code was exchanged for an access token |
executing | The token was consumed and the service account creation workflow is running |
completed | The workflow finished successfully and the service account is ready |
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
- Review the OAuth API Reference for detailed endpoint documentation
- Check out the OAuth Quickstart Guide for working code examples
- Learn about Managing Credentials via API to rotate or revoke credentials after initial creation
- Learn about Authenticating Your Requests using the credentials you receive