Skip to content

Sign JWT logins in LOGIN_TOKEN and add the noon Marketplace adapter - #1236

Merged
helpcodeai merged 4 commits into
mainfrom
feat/noon-marketplace
Oct 24, 2026
Merged

helpcodeai merged 4 commits into
mainfrom
feat/noon-marketplace

Conversation

@helpcodeai

@helpcodeai helpcodeai commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

noon's Partner API logs in with a JWT the client signs with its service account key, not with a password, so a noon Marketplace adapter was not possible. This lets LOGIN_TOKEN sign that JWT for each login (#1235) and adds the noon-marketplace adapter (noon.com marketplace in the UAE, Saudi Arabia and Egypt) as its first user.

Changes

Engine

  • LOGIN_TOKEN takes an optional signedJwt block (privateKey, algorithm default RS256, claims, optional keyId, ttlSeconds, outputParam). Every login signs a new token (iat = now in whole seconds, random jti, then the claims; exp only with ttlSeconds), available to the login body as ${signedJwt}. With it, username and password are not required.
  • The signer is shared with the OAuth2 private_key_jwt client assertions: signJwt was extracted from signClientAssertion (same key parsing, algorithms and errors; the client assertion's claims are unchanged). A claim whose {{VARIABLE}} is empty fails the login with an error naming it; key errors never contain key material; the signed token is masked in the login debug log.
  • The LOGIN_TOKEN failure hint now says "credentials (email and password, or a signing key)".
  • catalog.spec.ts checks LOGIN_TOKEN adapters by the same rules as the engine: cookieName optional with cookieMode: "all", and with signedJwt a key and ${signedJwt} in the login body instead of username/password.
  • Docs: docs/connectors/login-token-auth.md (field reference, placeholder, "Signed JWT logins", security note) and docs/tool-definition.md.

Adapter noon-marketplace (intl, e-commerce, 27 tools; 545 adapters listed, up from 544)

  • Login: RS256 JWT with sub = NOON_KEY_ID, posted with NOON_PROJECT_CODE to /identity/public/v1/api/login; the session cookies (30 days) are sent back on every call, with User-Agent and X-Project. Variables: NOON_KEY_ID, NOON_PRIVATE_KEY, NOON_PROJECT_CODE, from the service account key file.
  • Reads: whoami, warehouses, categories and category attributes, product content, product groups, offers, prices, stock, FBPI orders, order customer details, shipments, purchase orders, return references, export categories and status, import status.
  • Writes installed switched off: upsert product, upsert product group, upsert prices, update stock, mark order items unavailable, create shipment, cancel shipment. On at install: generate noon AWB numbers and create an export (neither changes products, prices, stock or orders).
  • Left out: OAuth and API-user credential management, webhook destinations, sandbox orders, SKU rename/delete/mapping, invoice uploads (base64 PDF in the body), cross-border transfer prices.
  • Docs: https://noon-docs.noonpartners.dev/docs/getting-started/intro and the API reference page of each endpoint.

Cloud and self-hosted behave the same: the JWT is signed by the backend that runs the connector, and the private key is stored encrypted like any other credential.

Type

  • Bug fix
  • New feature
  • Documentation
  • Refactoring
  • Performance improvement
  • Other (describe below)

Testing

  • Added/updated unit tests
  • Tested manually (describe steps below)
  • No tests needed (explain why)

Not tested against a live noon account: we have no noon credentials. The adapter's live spec signs its own JWT and reads whoami, warehouses, categories and export categories: NOON_KEY_ID=… NOON_PRIVATE_KEY=… NOON_PROJECT_CODE=… RUN_NOON_MARKETPLACE_LIVE=1 npx jest src/adapters/intl/noon-marketplace (in packages/backend). The login endpoint itself answers an empty body with INVALID_ARGUMENT: Not enough segments, i.e. it expects exactly this JWT.

Commands (repository root unless noted):

  • packages/backend: npx jest src/connectors/engines/login-token src/connectors/engines/client-assertion: 79 passed. New signedJwt tests: login sends a valid RS256 token (signature checked with the public key), iat in seconds, jti per login, exp/kid only when configured, empty claim variable named, bad key not quoted, username/password still required without signedJwt.
  • packages/backend: npm test: first run 753 suites passed, 1 failed (catalog.spec.ts, the static check above, fixed in the last commit), 22,470 tests passed; npx jest src/adapters/catalog.spec.ts after the fix: 9,951 passed.
  • packages/backend: npx tsc --noEmit -p tsconfig.json clean; npm run lint 0 errors, 11 pre-existing warnings (unrelated eslint --fix rewrites reverted).
  • node scripts/validate-adapters.mjs --warn: exit 0, no warning for noon-marketplace.
  • node scripts/regenerate-catalog.mjs, then node scripts/adapter-count.mjs --check: OK: every quoted count equals 545 adapters (25 keyless, 8383 tools). (after the rebase on Add 15 catalog adapters and fill gaps in 19 existing ones #1233)

Rebased on main after #1233 merged: counts updated to 545, catalog regenerated; npx jest src/adapters/catalog.spec.ts src/connectors/engines/login-token.service.spec.ts src/connectors/engines/client-assertion src/adapters/intl/noon-marketplace.live.spec.ts: 4 suites, 10,345 passed, 1 skipped (the gated live call); npx tsc --noEmit -p tsconfig.json clean.

Checklist

  • My code follows the existing code style
  • I have tested my changes locally
  • I have updated documentation (if applicable)
  • All existing tests pass (npm test)
  • This PR has a descriptive title

Related Issues

Closes #1235

@helpcodeai
helpcodeai force-pushed the feat/noon-marketplace branch from a5c2355 to e1d25a6 Compare October 24, 2026 18:45
@helpcodeai
helpcodeai enabled auto-merge (squash) October 24, 2026 19:06
@helpcodeai
helpcodeai merged commit ea63a3e into main Oct 24, 2026
14 checks passed
@helpcodeai
helpcodeai deleted the feat/noon-marketplace branch October 24, 2026 19:16
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 24, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LOGIN_TOKEN: sign a JWT for the login request (noon Partner API)

1 participant