--- id: o-auth-service-create-token title: "CreateToken" description: "Exchanges an authorization code for an OAuth access token." sidebar_label: "CreateToken" hide_title: true hide_table_of_contents: true sidebar_class_name: "post api-method" --- # CreateToken `POST https://noon-api-gateway.noon.partners/identity/oauth/v1/token/create` ## Usage Plan | Type | Requests | Time limit (seconds) | | --- | ---: | ---: | | Rate | 1500 | 60 | | Burst | 1500 | 60 | Learn more about rate limits and usage plans in the [Rate Limiting](/docs/overview/rate-limiting) guide. Exchanges an authorization code for an OAuth access token. Provide the authorization code received from the OAuth consent flow along with your client credentials (client_id and client_secret). If your OAuth client is configured to require PKCE, the authorization flow must have started with a code_challenge and you must send the matching code_verifier here, or the exchange is rejected. On success, returns a JWT access token, its expiry duration, granted scopes, and the seller's authorized project code. ## Request No parameters documented. ### application/json - `grant_type` (string, required): The OAuth grant type. Use 'authorization_code' for standard OAuth code exchange. - `code` (string, required): The authorization code received from the OAuth consent redirect. - `client_id` (string, required): Your OAuth client ID issued during app registration. - `client_secret` (string, required): Your OAuth client secret issued during app registration. - `code_verifier` (string): PKCE code verifier (RFC 7636): the high-entropy random string, 43-128 characters long, whose SHA-256 hash was sent as code_challenge when the authorization flow started (only S256 method is supported as a code_challenge method). Required whenever your OAuth client is configured to require PKCE. Clients not configured that way may still adopt PKCE per flow, in which case this is required for any flow that sent a code_challenge. Omit this field for flows that did not send a code_challenge. Use a fresh verifier for every authorization flow and never reuse one. Nullable. ## Responses ### 200 A successful response. ### application/json - `access_token` (string, required): The JWT token to use for token exchange. - `token_type` (string enum, required): The type of token issued (Bearer). Allowed values: `TOKEN_TYPE_UNSPECIFIED`, `TOKEN_TYPE_BEARER`. Default: `TOKEN_TYPE_UNSPECIFIED`. - `expires_in` (string, required): Duration until the token expires. - `scopes` (string[], required): List of scopes granted to the token. - `project_code` (string, required): The seller's authorized project code associated with this token. ### default An unexpected error response. ### application/json The `Status` type defines a logical error model that is suitable for different programming environments, including REST APIs and RPC APIs. It is used by [gRPC](https://github.com/grpc). Each `Status` message contains three pieces of data: error code, error message, and error details. You can find out more about this error model and how to work with it in the [API Design Guide](https://cloud.google.com/apis/design/errors). - `status_id` (integer (int32)) - `status_code` (string) - `message` (string) - `details` (object[]) ## Code Examples ### python ```python # Authentiction code is added below, to know more about authentication # visit: https://noon-docs.noonpartners.dev/docs/authentication/authenticating-requests import json import time import uuid import jwt import requests BASE_URL = "https://noon-api-gateway.noon.partners" USER_AGENT = "NoonApiClient/1.0" with open("noon_credentials_sensitive.json", "r", encoding="utf-8") as file: credentials = json.load(file) # Create a signed RS256 JWT for the login request. def create_jwt(): return jwt.encode( { "sub": credentials["key_id"], "iat": int(time.time()), "jti": str(uuid.uuid4()), }, credentials["private_key"], algorithm="RS256", ) # Log in and return a requests session that keeps auth cookies. def get_authenticated_session(): session = requests.Session() session.headers.update({"User-Agent": USER_AGENT}) response = session.post( f"{BASE_URL}/identity/public/v1/api/login", json={ "token": create_jwt(), "default_project_code": credentials["project_code"], }, ) if response.status_code != 200: raise Exception(f"Login failed with HTTP {response.status_code}: {response.text}") return session session = get_authenticated_session() payload = '' headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } res = session.post("https://noon-api-gateway.noon.partners/identity/oauth/v1/token/create", data=json.dumps(payload), headers=headers) ``` ### go ```go // Authentiction code is added below, to know more about authentication // visit: https://noon-docs.noonpartners.dev/docs/authentication/authenticating-requests package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" "net/http/cookiejar" "os" "time" // go get github.com/google/uuid github.com/golang-jwt/jwt/v5 "github.com/golang-jwt/jwt/v5" "github.com/google/uuid" ) const BASE_URL = "https://noon-api-gateway.noon.partners" const USER_AGENT = "NoonApiClient/1.0" type Credentials struct { PrivateKey string `json:"private_key"` KeyID string `json:"key_id"` ProjectCode string `json:"project_code"` } var credentials Credentials func check(err error) { if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } func read_credentials() Credentials { file, err := os.ReadFile("noon_credentials_sensitive.json") check(err) var credentials Credentials check(json.Unmarshal(file, &credentials)) return credentials } func create_jwt() string { private_key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(credentials.PrivateKey)) check(err) token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{ "sub": credentials.KeyID, "iat": time.Now().Unix(), "jti": uuid.NewString(), }) signed_token, err := token.SignedString(private_key) check(err) return signed_token } func get_authenticated_session() *http.Client { jar, err := cookiejar.New(nil) check(err) client := &http.Client{Jar: jar} body, _ := json.Marshal(map[string]string{ "token": create_jwt(), "default_project_code": credentials.ProjectCode, }) req, err := http.NewRequest( "POST", BASE_URL+"/identity/public/v1/api/login", bytes.NewReader(body), ) check(err) req.Header.Set("User-Agent", USER_AGENT) req.Header.Set("Content-Type", "application/json") resp, err := client.Do(req) check(err) defer resp.Body.Close() response_body, _ := io.ReadAll(resp.Body) if resp.StatusCode != 200 { fmt.Fprintf(os.Stderr, "Login failed with HTTP %d: %s\n", resp.StatusCode, response_body) os.Exit(1) } return client } func main() { credentials = read_credentials() client := get_authenticated_session() url := "https://noon-api-gateway.noon.partners/identity/oauth/v1/token/create" method := "POST" payload := strings.NewReader(``) req, err := http.NewRequest(method, url, payload) if err != nil { fmt.Println(err) return } req.Header.Add("Content-Type", "application/json") req.Header.Add("Accept", "application/json") res, err := client.Do(req) if err != nil { fmt.Println(err) return } defer res.Body.Close() body, err := io.ReadAll(res.Body) if err != nil { fmt.Println(err) return } fmt.Println(string(body)) } ``` ### java ```java // Authentiction code is added below, to know more about authentication // visit: https://noon-docs.noonpartners.dev/docs/authentication/authenticating-requests import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm; import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.*; import java.io.File; import java.security.KeyFactory; import java.security.interfaces.RSAPrivateKey; import java.security.spec.PKCS8EncodedKeySpec; import java.time.Instant; import java.util.*; public class Main { private static RSAPrivateKey readPrivateKey(String pem) throws Exception { String stripped = pem .replace("-----BEGIN PRIVATE KEY-----", "") .replace("-----END PRIVATE KEY-----", "") .replaceAll("\\s", ""); byte[] encoded = Base64.getDecoder().decode(stripped); return (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(encoded)); } static OkHttpClient getAuthenticatedClient() throws Exception { ObjectMapper mapper = new ObjectMapper(); Map credentials = mapper.readValue(new File("noon_credentials_sensitive.json"), Map.class); String privateKeyPem = (String) credentials.get("private_key"); String keyId = (String) credentials.get("key_id"); String projectCode = (String) credentials.get("project_code"); RSAPrivateKey privateKey = readPrivateKey(privateKeyPem); long now = Instant.now().getEpochSecond(); String jti = UUID.randomUUID().toString(); String token = JWT.create() .withSubject(keyId) .withIssuedAt(java.util.Date.from(Instant.ofEpochSecond(now))) .withJWTId(jti) .sign(Algorithm.RSA256(null, privateKey)); OkHttpClient client = new OkHttpClient.Builder() .cookieJar(new CookieJar() { private List cookies = new ArrayList<>(); @Override public void saveFromResponse(HttpUrl url, List cookies) { this.cookies = cookies; } @Override public List loadForRequest(HttpUrl url) { return cookies != null ? cookies : new ArrayList<>(); } }) .build(); Map loginPayload = new HashMap<>(); loginPayload.put("token", token); loginPayload.put("default_project_code", projectCode); RequestBody loginBody = RequestBody.create( mapper.writeValueAsString(loginPayload), MediaType.parse("application/json") ); Request loginRequest = new Request.Builder() .url("https://noon-api-gateway.noon.partners/identity/public/v1/api/login") .post(loginBody) .header("User-Agent", "REPLACE_WITH_YOUR_USER_AGENT") .build(); try (Response loginResponse = client.newCall(loginRequest).execute()) { if (!loginResponse.isSuccessful()) { throw new RuntimeException( "Login failed: " + loginResponse.code() + " " + loginResponse.body().string() ); } } return client; } public static void main(String[] args) throws Exception { OkHttpClient client = getAuthenticatedClient(); MediaType mediaType = MediaType.parse("application/json"); RequestBody body = RequestBody.create(mediaType, ""); Request request = new Request.Builder() .url("https://noon-api-gateway.noon.partners/identity/oauth/v1/token/create") .method("POST", body) .addHeader("Content-Type", "application/json") .addHeader("Accept", "application/json") .build(); Response response = client.newCall(request).execute(); } } ``` ### nodejs ```javascript // Authentiction code is added below, to know more about authentication // visit: https://noon-docs.noonpartners.dev/docs/authentication/authenticating-requests import fs from 'fs'; import crypto from 'crypto' const credentials = JSON.parse( fs.readFileSync('noon_credentials_sensitive.json', 'utf8'), ); const BASE_URL = 'https://noon-api-gateway.noon.partners'; const USER_AGENT = 'NoonApiClient/1.0'; function base64url(value) { return Buffer.from(value).toString('base64url'); } function create_jwt() { const header = base64url(JSON.stringify({ alg: 'RS256', typ: 'JWT' })); const payload = base64url(JSON.stringify({ sub: credentials.key_id, iat: Math.floor(Date.now() / 1000), jti: crypto.randomUUID(), })); const signing_input = `${header}.${payload}`; const signature = crypto.sign( 'RSA-SHA256', Buffer.from(signing_input), credentials.private_key, ); return `${signing_input}.${base64url(signature)}`; } function get_cookie_header(response) { const set_cookie_headers = response.headers.getSetCookie?.() || [response.headers.get('set-cookie')].filter(Boolean); return set_cookie_headers .map((cookie) => cookie.split(';')[0]) .join('; '); } async function get_authenticated_session() { const response = await fetch(`${BASE_URL}/identity/public/v1/api/login`, { method: 'POST', headers: { 'User-Agent': USER_AGENT, 'Content-Type': 'application/json', }, body: JSON.stringify({ token: create_jwt(), default_project_code: credentials.project_code, }), }); if (response.status !== 200) { throw new Error(`Login failed with HTTP ${response.status}: ${await response.text()}`); } const cookie_header = get_cookie_header(response); return { get: (path) => fetch(`${BASE_URL}${path}`, { headers: { 'User-Agent': USER_AGENT, Cookie: cookie_header }, }), post: (path, body) => fetch(`${BASE_URL}${path}`, { method: 'POST', headers: { 'User-Agent': USER_AGENT, 'Content-Type': 'application/json', Cookie: cookie_header }, body: JSON.stringify(body), }), }; } const session = await get_authenticated_session(); const res = await session.post('/identity/oauth/v1/token/create'); const data = await res.text(); ``` ### php ```php $credentials['key_id'], 'iat' => time(), 'jti' => Uuid::uuid4()->toString(), ], $credentials['private_key'], 'RS256'); } function get_authenticated_session(): Client { global $credentials; $client = new Client([ 'base_uri' => BASE_URL, 'cookies' => new CookieJar(), 'http_errors' => false, 'headers' => ['User-Agent' => USER_AGENT], ]); $response = $client->post('/identity/public/v1/api/login', [ 'json' => [ 'token' => create_jwt(), 'default_project_code' => $credentials['project_code'], ], ]); if ($response->getStatusCode() !== 200) { throw new Exception( 'Login failed with HTTP ' . $response->getStatusCode() . ': ' . $response->getBody() ); } return $client; } $session = get_authenticated_session(); $body = ''; $response = $session->post('/identity/oauth/v1/token/create', ['json' => json_decode($body, true)]); $data = $response->getBody()->getContents(); ``` ### csharp ```csharp // Authentiction code is added below, to know more about authentication // visit: https://noon-docs.noonpartners.dev/docs/authentication/authenticating-requests using System.Net; using System.Net.Http.Json; using System.Security.Cryptography; using System.Text; using System.Text.Json; const string BASE_URL = "https://noon-api-gateway.noon.partners"; const string USER_AGENT = "NoonApiClient/1.0"; var credentials = JsonSerializer.Deserialize>( File.ReadAllText("noon_credentials_sensitive.json") )!; string base64url(byte[] value) => Convert.ToBase64String(value).TrimEnd('=').Replace('+', '-').Replace('/', '_'); string create_jwt() { var header = base64url(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(new { alg = "RS256", typ = "JWT" }))); var payload = base64url(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(new { sub = credentials["key_id"], iat = DateTimeOffset.UtcNow.ToUnixTimeSeconds(), jti = Guid.NewGuid().ToString() }))); var signingInput = $"{header}.{payload}"; using var rsa = RSA.Create(); rsa.ImportFromPem(credentials["private_key"]); var signature = rsa.SignData( Encoding.UTF8.GetBytes(signingInput), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1 ); return $"{signingInput}.{base64url(signature)}"; } async Task get_authenticated_session() { var handler = new HttpClientHandler { CookieContainer = new CookieContainer() }; var client = new HttpClient(handler) { BaseAddress = new Uri(BASE_URL) }; client.DefaultRequestHeaders.UserAgent.ParseAdd(USER_AGENT); var response = await client.PostAsJsonAsync("/identity/public/v1/api/login", new { token = create_jwt(), default_project_code = credentials["project_code"] }); if (response.StatusCode != HttpStatusCode.OK) { throw new Exception( $"Login failed with HTTP {(int)response.StatusCode}: {await response.Content.ReadAsStringAsync()}" ); } return client; } var session = await get_authenticated_session(); var content = new StringContent("", null, "application/json"); var response = await session.PostAsync("/identity/oauth/v1/token/create", content); response.EnsureSuccessStatusCode(); Console.WriteLine(await response.Content.ReadAsStringAsync()); ``` ### curl ```bash # Authentiction code is added below, to know more about authentication # visit: https://noon-docs.noonpartners.dev/docs/authentication/authenticating-requests #!/usr/bin/env bash set -euo pipefail NOON_BASE_URL="${NOON_BASE_URL:-https://noon-api-gateway.noon.partners}" CREDENTIALS_FILE="${NOON_CREDENTIALS_FILE:-noon_credentials_sensitive.json}" NOON_USER_AGENT="${NOON_USER_AGENT:-NoonApiClient/1.0}" COOKIE_JAR="$(mktemp "${TMPDIR:-/tmp}/noon_cookies.XXXXXX")" PRIVATE_KEY_FILE="$(mktemp "${TMPDIR:-/tmp}/noon_private_key.XXXXXX")" trap 'rm -f "$COOKIE_JAR" "$PRIVATE_KEY_FILE"' EXIT cred() { jq -r --arg key "$1" '.[$key]' "$CREDENTIALS_FILE"; } b64url() { openssl base64 -A | tr '+/' '-_' | tr -d '='; } create_jwt() { cred private_key > "$PRIVATE_KEY_FILE" chmod 600 "$PRIVATE_KEY_FILE" header_b64="$(printf '%s' '{"alg":"RS256","typ":"JWT"}' | b64url)" payload_json="$( jq -cn \ --arg sub "$(cred key_id)" \ --argjson iat "$(date +%s)" \ --arg jti "$(uuidgen | tr '[:upper:]' '[:lower:]')" \ '{sub:$sub,iat:$iat,jti:$jti}' )" payload_b64="$(printf '%s' "$payload_json" | b64url)" signing_input="${header_b64}.${payload_b64}" signature_b64="$( printf '%s' "$signing_input" \ | openssl dgst -sha256 -sign "$PRIVATE_KEY_FILE" -binary \ | b64url )" printf '%s.%s\n' "$signing_input" "$signature_b64" } get_authenticated_session() { body="$( jq -cn \ --arg token "$(create_jwt)" \ --arg project_code "$(cred project_code)" \ '{token:$token,default_project_code:$project_code}' )" login_result="$( curl --silent --show-error \ --request POST "${NOON_BASE_URL}/identity/public/v1/api/login" \ --header "User-Agent: ${NOON_USER_AGENT}" \ --header "Content-Type: application/json" \ --cookie-jar "$COOKIE_JAR" \ --data "$body" \ --write-out $'\n%{http_code}' )" login_status="${login_result##*$'\n'}" login_body="${login_result%$'\n'*}" if [ "$login_status" != "200" ]; then echo "Login failed with HTTP $login_status:" >&2 echo "$login_body" >&2 exit 1 fi printf '%s\n' "$COOKIE_JAR" } SESSION_COOKIE_JAR="$(get_authenticated_session)" curl -L -X POST "${NOON_BASE_URL}/identity/oauth/v1/token/create" \ --cookie "$SESSION_COOKIE_JAR" \ --header "User-Agent: ${NOON_USER_AGENT}" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -d '' ```