Skip to main content

OAuth sign-in for assistants

How an AI app signs a person in to TradeSender, from discovery and registration to the authorization code, PKCE and the token.

An AI app gets its token for the MCP server through OAuth 2.1: the authorization code flow with PKCE. Every app is a public client. It holds no secret.

This sign-in is only for /mcp. It does not give a third-party app access to /api/v1: for that, a member makes an API key.

Discovery

Two documents say where everything is.

https://app.tradesender.co.uk/.well-known/oauth-protected-resource/mcp
https://app.tradesender.co.uk/.well-known/oauth-authorization-server

The first (RFC 9728) names the resource, https://app.tradesender.co.uk/mcp, and its authorization server. The second (RFC 8414) lists the endpoints:

EndpointAddress
AuthorizationGET /oauth/authorize
TokenPOST /oauth/token
RegistrationPOST /oauth/register
RevocationPOST /oauth/revoke

It also states what is supported: the code response type, the authorization_code grant, S256 code challenges, no client authentication, Client ID Metadata Documents, and the iss parameter on the answer.

Say who you are

An app identifies itself in one of two ways.

Publish a metadata document. Use an https address you control as your client_id, and serve JSON there with client_id (the same address), client_name and redirect_uris. TradeSender fetches it when a person connects and keeps it for an hour. The address must have a path, use port 443 and answer without a redirect, and the document must be under 5,000 bytes. The person then sees your name and the host you published from.

Register. POST /oauth/register with client_name and redirect_uris, and use the client_id that comes back. The person sees your name as "an app calling itself", because nothing about a registered name is checked.

curl -X POST "https://app.tradesender.co.uk/oauth/register" \
  -H "Content-Type: application/json" \
  -d '{ "client_name": "My assistant", "redirect_uris": ["https://assistant.example/callback"] }'

You may give from one to ten redirect addresses. Each is an https address, an http address on the person's own device (127.0.0.1, ::1 or localhost, where any port matches), or an app's own link such as myapp://callback. A fragment is not allowed.

Ask the person

Send the person's browser to /oauth/authorize with:

ParameterValue
response_typecode
client_idYour metadata address or registered id
redirect_uriOne you registered. Optional when you registered only one.
code_challengeThe S256 challenge for your verifier
code_challenge_methodS256
stateYours, returned unchanged
resourceOptional. If sent, https://app.tradesender.co.uk or an address under it.

TradeSender signs the person in if needed and asks them to allow the connection, naming the workspace, your app and where they will be sent back. They have 30 minutes to answer.

Their browser returns to your redirect_uri with code, your state and iss (RFC 9207), or with error=access_denied if they chose Cancel.

An unknown client_id, or a redirect_uri you did not register, is refused on the spot with a plain message and no redirect. Other faults return to your redirect_uri as unsupported_response_type, invalid_request or invalid_target.

Get the token

Swap the code within two minutes:

curl -X POST "https://app.tradesender.co.uk/oauth/token" \
  -d grant_type=authorization_code \
  -d code="$CODE" \
  -d client_id="$CLIENT_ID" \
  -d code_verifier="$VERIFIER" \
  -d redirect_uri="https://assistant.example/callback"
{ "access_token": "…", "token_type": "Bearer" }

A code works once. A second attempt with the same code is refused and also revokes the token the first attempt was given.

There is no refresh token and no expiry. The token works until the connection ends.

When a connection ends

  • The person chooses Disconnect on the assistant's sheet in Settings, Connected apps.
  • Your app calls POST /oauth/revoke with token (RFC 7009). The answer is 200 whether or not the token was one of ours.
  • The person changes or resets their password, leaves the workspace, or is deactivated or removed.
  • The workspace is deleted.

After that /mcp answers 401 and the app starts again from discovery.

Errors

The token and registration endpoints answer 400 with an OAuth error:

{ "error": "invalid_grant", "error_description": "The code is invalid or has expired" }
ErrorCause
invalid_redirect_uriA redirect address at registration is not one of the allowed kinds.
unsupported_grant_typegrant_type is not authorization_code.
invalid_grantThe code is wrong, expired or already used, or the verifier, client or redirect address does not match the request that made it.

These endpoints allow 300 requests a minute from one address.

Checked against the app on 18 October 2026. Still stuck? Ask usAsk us.