Skip to content

Commit 90b0ab6

Browse files
authored
AIDX-319 Add python counterparts to MCP get started pages (#302)
* add python counterparts for mcp quickstarts * update * fix code block language in exchange-access-token-js.mdx * fix broken link * adds code snippet * addressing feedback * addressing feedback * addressing feedback * address feedback * simplify env file creation
1 parent 7c17cec commit 90b0ab6

File tree

9 files changed

+362
-178
lines changed

9 files changed

+362
-178
lines changed

auth4genai/mcp/get-started/call-your-apis-on-users-behalf.mdx

Lines changed: 83 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ import CreateMCPAPI from "/snippets/mcp/get-started/create-mcp-api.mdx";
1717
import AssignPermissionsToRoles from "/snippets/mcp/get-started/config-tenant/assign-permissions-to-roles.mdx";
1818
import { DownloadQuickstartButton } from "/snippets/download-quickstart/DownloadQuickstartButton.jsx";
1919
import MCPGetStartedTestingInstructions from "/snippets/mcp/get-started/testing-instructions.mdx";
20+
import CreateEnvFile from "/snippets/mcp/get-started/call-your-apis/create-env-file.mdx";
21+
import CustomTokenExchangeAction from "/snippets/mcp/get-started/call-your-apis/custom-token-exchange-action.mdx";
22+
import RunMcpServerJs from "/snippets/mcp/get-started/call-your-apis/run-mcp-server-js.mdx";
23+
import RunMcpServerPython from "/snippets/mcp/get-started/call-your-apis/run-mcp-server-python.mdx";
24+
import ExchangeAccessTokenJs from "/snippets/mcp/get-started/call-your-apis/exchange-access-token-js.mdx";
25+
import ExchangeAccessTokenPython from "/snippets/mcp/get-started/call-your-apis/exchange-access-token-python.mdx";
2026

2127
To call your APIs on behalf of your users, the MCP server needs to exchange the Auth0 access token it received from the MCP client (with the audience set to the MCP server itself) for a new Auth0 access token with the audience set to your API.
2228

@@ -25,7 +31,7 @@ In Auth0, this is called Custom Token Exchange and uses [RFC 8693](https://www.r
2531
By the end of this quickstart, you should have an MCP server that can:
2632

2733
* Exchange an Auth0 access token for another Auth0 access token with a different audience using Custom Token Exchange
28-
* Verify the access token using the `@auth0/auth0-api-js` library (which uses `jose` under the hood) against your tenant JWKS, enforcing issuer, audience, and RS256
34+
* Verify the access token using the `@auth0/auth0-api-js` library (which uses `jose` under the hood) or the `auth0-api-python` library for Python against your tenant JWKS, enforcing issuer, audience, and RS256
2935

3036
<MCPGetStartedPrerequisites />
3137

@@ -84,173 +90,110 @@ auth0 api post resource-servers --data '{
8490

8591
Save the `Audience` from the command output; you'll need it in a later step.
8692

87-
93+
## Sample app
8894
<Tabs>
89-
<Tab title="Use sample app (recommended)">
90-
Start by downloading the sample app for this quickstart. The sample includes a FastMCP MCP server with an Auth0 integration and a protected API built with
91-
[Fastify](https://fastify.dev/).
92-
93-
<DownloadQuickstartButton
94-
category="auth-for-mcp"
95-
framework="fastmcp-mcp-customtokenexchange-js"
96-
/>
97-
98-
Once downloaded, extract the files and open the project in your preferred IDE.
99-
</Tab>
100-
<Tab title="Clone GitHub repository">
101-
Clone the repository and navigate to the sample app folder which includes a FastMCP MCP server with an Auth0 integration and a protected API built with
102-
[Fastify](https://fastify.dev/).
103-
104-
```shell wrap lines
105-
git clone https://github.com/auth0-samples/auth0-ai-samples.git
106-
cd auth0-ai-samples/auth-for-mcp/fastmcp-mcp-customtokenexchange-js
107-
```
108-
109-
Once cloned, open the project in your preferred IDE.
110-
</Tab>
111-
</Tabs>
112-
113-
The sample app demonstrates custom token exchange with a `greet` tool that calls your protected API on behalf of the authenticated user.
114-
115-
## Install packages
116-
117-
Ensure you have npm installed or follow the instructions to [install npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) in its documentation. In the `fastmcp-mcp-customtokenexchange-js` directory, install the required packages:
118-
119-
```shell
120-
npm install
121-
```
122-
123-
## Create your environment file
124-
125-
In the `fastmcp-mcp-customtokenexchange-js` directory, run the following command to create a new `.env` file populated with all the required environment variables:
126-
127-
```shell wrap lines expandable
128-
CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) \
129-
&& CLIENT_SECRET=$(jq -r '.client_secret' auth0-app-details.json) \
130-
&& DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') \
131-
&& touch .env \
132-
&& echo "AUTH0_DOMAIN=${DOMAIN}" > .env \
133-
&& echo "AUTH0_AUDIENCE=http://localhost:3001/" >> .env \
134-
&& echo "PORT=3001" >> .env \
135-
&& echo "MCP_SERVER_URL=http://localhost:3001/" >> .env \
136-
&& echo "MCP_AUTH0_CLIENT_ID=${CLIENT_ID}" >> .env \
137-
&& echo "MCP_AUTH0_CLIENT_SECRET=${CLIENT_SECRET}" >> .env \
138-
&& echo "MCP_AUTH0_SUBJECT_TOKEN_TYPE=urn:fastmcp:mcp" >> .env \
139-
&& echo "MCP_AUTH0_EXCHANGE_SCOPE=read:tasks" >> .env \
140-
&& echo "API_AUTH0_AUDIENCE=http://localhost:8787/" >> .env \
141-
&& echo "API_BASE_URL=http://localhost:8787/" >> .env \
142-
&& rm auth0-app-details.json \
143-
&& echo ".env file created with your Auth0 details:" \
144-
&& cat .env
145-
```
146-
147-
To get your Auth0 application’s `AUTH0_DOMAIN`, run the following command:
148-
149-
```shell
150-
auth0 tenants list
151-
```
95+
<Tab title="Javascript" icon="js">
96+
<Tabs>
97+
<Tab title="Use sample app (recommended)">
98+
Start by downloading the sample app for this quickstart. The sample includes a FastMCP MCP server with an Auth0 integration and a protected API built with
99+
[Fastify](https://fastify.dev/).
152100

153-
Copy the domain under `TENANT` from the output and update the corresponding variable in the `.env` file.
101+
<DownloadQuickstartButton
102+
category="auth-for-mcp"
103+
framework="fastmcp-mcp-customtokenexchange-js"
104+
/>
154105

155-
For `MCP_AUTH0_CLIENT_ID` and `MCP_AUTH0_CLIENT_SECRET` you will use the values obtained from the [Create an Application for your MCP server](./call-your-apis-on-users-behalf#create-an-application-for-your-mcp-server) step.
106+
Once downloaded, extract the files and open the project in your preferred IDE.
107+
</Tab>
108+
<Tab title="Clone GitHub repository">
109+
Clone the repository and navigate to the sample app folder which includes a FastMCP MCP server with an Auth0 integration and a protected API built with
110+
[Fastify](https://fastify.dev/).
156111

157-
## Use Custom Token Exchange Action
112+
```shell wrap lines
113+
git clone https://github.com/auth0-samples/auth0-ai-samples.git
114+
cd auth0-ai-samples/auth-for-mcp/fastmcp-mcp-customtokenexchange-js
115+
```
158116

159-
This Action is the server-side logic Auth0 executes to perform the token exchange. It is necessary because the MCP server receives an access token from the client (with the MCP server as its audience) and must exchange it for a new token (with the upstream API as the audience). This Action validates the original token and mints the new one.
117+
Once cloned, open the project in your preferred IDE.
118+
</Tab>
119+
</Tabs>
160120

161-
The Custom Token Exchange Action is available as part of Custom Token Exchange Early Access. Navigate to [the On-behalf-of token exchange for first-party apps template available here](https://manage.auth0.com/#/actions/library/templates/templates/daeda4e8-8da2-4abb-afb5-ac09df0ebb2a) and click on **Use This Template**.
121+
The sample app demonstrates custom token exchange with a `greet` tool that calls your protected API on behalf of the authenticated user.
162122

163-
<Frame>
164-
<img
165-
src="/img/mcp/cte_action_template_page.png"
166-
alt="Action On-behalf-of token exchange for first-party apps template page"
167-
/>
168-
</Frame>
123+
## Install packages
169124

170-
This will open a modal for you to name the action:
125+
Ensure you have npm installed or follow the instructions to [install npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) in its documentation. In the `fastmcp-mcp-customtokenexchange-js` directory, install the required packages:
171126

172-
<Frame>
173-
<img
174-
class="img-sizing"
175-
src="/img/mcp/cte_action_creation_modal.png"
176-
alt="Action creation modal"
177-
/>
178-
</Frame>
127+
```shell
128+
npm install
129+
```
179130

180-
Once the action is created, you can **Deploy** it. When you deploy the Action, Auth0 assigns it an Action ID. You still need to add your custom logic to the Action, but first, get the Action ID to create the Custom Token Exchange Profile.
131+
## Create your environment file
132+
<CreateEnvFile/>
181133

182-
## Set up the token exchange profile
134+
## Use Custom Token Exchange Action
135+
<CustomTokenExchangeAction/>
183136

184-
<CreateProfile />
137+
## Set up the token exchange profile
138+
<CreateProfile />
185139

186-
## Run the MCP server and the API
140+
## Run the MCP server and the API
141+
<RunMcpServerJs/>
187142

188-
Run this command to start your server:
143+
## Exchange your access token
144+
<ExchangeAccessTokenJs/>
145+
</Tab>
189146

190-
```shell
191-
npm run start
192-
```
147+
<Tab title="Python" icon="python">
148+
<Tabs>
149+
<Tab title="Use sample app (recommended)">
150+
Start by downloading the sample app for this quickstart. The sample includes a FastMCP MCP server with an Auth0 integration and a protected Starlette-based API.
193151

194-
And in a separate window run this command to start the API:
152+
<DownloadQuickstartButton
153+
category="auth-for-mcp"
154+
framework="fastmcp-mcp-customtokenexchange-python"
155+
/>
195156

196-
```shell
197-
npm run start:api
198-
```
157+
Once downloaded, extract the files and open the project in your preferred IDE.
158+
</Tab>
159+
<Tab title="Clone GitHub repository">
160+
Clone the repository and navigate to the sample app folder which includes a FastMCP MCP server with an Auth0 integration and a protected Starlette-based API.
199161

200-
## Exchange your access token
162+
```shell wrap lines
163+
git clone https://github.com/auth0-samples/auth0-ai-samples.git
164+
cd auth0-ai-samples/auth-for-mcp/fastmcp-mcp-customtokenexchange-python
165+
```
201166

202-
To call your APIs on behalf of your users, the MCP server needs to exchange the Auth0 access token it received from the MCP client (with the audience set to the MCP server itself) for a new Auth0 access token with the audience set to your API. In Auth0, this is called Custom Token Exchange and uses [RFC 8693](https://www.rfc-editor.org/rfc/rfc8693.html).
167+
Once cloned, open the project in your preferred IDE.
168+
</Tab>
169+
</Tabs>
203170

204-
### The Orchestrator: `bearerForUpstream`
171+
The sample app demonstrates custom token exchange with a `greet` tool that calls your protected API on behalf of the authenticated user.
205172

206-
The process begins with the `bearerForUpstream` function. Its main job is to take the initial token (the `subjectToken`), manage the exchange process, and handle any potential errors gracefully.
173+
## Install packages
207174

208-
This function serves as a safe wrapper around our exchange logic.
175+
Ensure you have poetry installed or follow the instructions to [install poetry](https://python-poetry.org/docs/) in its documentation. In the `fastmcp-mcp-customtokenexchange-python` directory, install the required packages:
209176

210-
```shell wrap lines highlight={5}
211-
async function bearerForUpstream(subjectToken: string) {
212-
if (!subjectToken) return { token: null, scopes: null };
177+
```shell
178+
poetry install
179+
```
213180

214-
try {
215-
const result = await exchangeCustomToken(subjectToken);
216-
return {
217-
token: result.accessToken,
218-
scopes: result.scope,
219-
}
220-
} catch (err) {
221-
console.error('Error during token exchange:', err);
222-
throw err;
223-
}
224-
}
225-
```
181+
## Create your environment file
182+
<CreateEnvFile/>
226183

227-
As you can see, it calls `exchangeCustomToken` and, on a successful exchange, returns the new `accessToken` and its associated scope. If the exchange fails, it logs the error and re-throws it to be handled upstream.
184+
## Use Custom Token Exchange Action
185+
<CustomTokenExchangeAction/>
228186

229-
### The core logic: `exchangeCustomToken`
187+
## Set up the token exchange profile
188+
<CreateProfile />
230189

231-
This function, located in `src/auth0.ts`, contains the actual token exchange logic. It uses the `ApiClient` from the `auth0-api-js` SDK to simplify the interaction with Auth0's `/oauth/token` endpoint.
190+
## Run the MCP server and the API
191+
<RunMcpServerPython/>
232192

233-
First, we initialize the `ApiClient` with the credentials of the application performing the exchange:
234-
235-
```javascript wrap lines
236-
const exchangeClient = new ApiClient({
237-
domain: AUTH0_DOMAIN,
238-
audience: API_AUTH0_AUDIENCE,
239-
clientId: MCP_AUTH0_CLIENT_ID,
240-
clientSecret: MCP_AUTH0_CLIENT_SECRET,
241-
});
242-
```
243-
With the client configured, the `exchangeCustomToken` function calls the `getTokenByExchangeProfile` method. This method implements the [Custom Token Exchange](https://auth0.com/docs/authenticate/custom-token-exchange) flow.
244-
245-
```javascript wrap lines
246-
export async function exchangeCustomToken(subjectToken: string) {
247-
return await exchangeClient.getTokenByExchangeProfile(subjectToken, {
248-
subjectTokenType: MCP_AUTH0_SUBJECT_TOKEN_TYPE,
249-
audience: API_AUTH0_AUDIENCE,
250-
...(MCP_AUTH0_EXCHANGE_SCOPE && { scope: MCP_AUTH0_EXCHANGE_SCOPE }),
251-
});
252-
}
253-
```
193+
## Exchange your access token
194+
<ExchangeAccessTokenPython/>
195+
</Tab>
196+
</Tabs>
254197

255198
<MCPGetStartedTestingInstructions />
256199

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
From the root of your sample app directory, run the following command to create a new `.env` file populated with all the required environment variables:
2+
3+
```shell wrap lines expandable
4+
CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) \
5+
&& CLIENT_SECRET=$(jq -r '.client_secret' auth0-app-details.json) \
6+
&& DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') \
7+
&& touch .env \
8+
&& echo "AUTH0_DOMAIN=${DOMAIN}" > .env \
9+
&& echo "AUTH0_AUDIENCE=http://localhost:3001/" >> .env \
10+
&& echo "PORT=3001" >> .env \
11+
&& echo "MCP_SERVER_URL=http://localhost:3001/" >> .env \
12+
&& echo "MCP_AUTH0_CLIENT_ID=${CLIENT_ID}" >> .env \
13+
&& echo "MCP_AUTH0_CLIENT_SECRET=${CLIENT_SECRET}" >> .env \
14+
&& echo "MCP_AUTH0_SUBJECT_TOKEN_TYPE=urn:fastmcp:mcp" >> .env \
15+
&& echo "MCP_AUTH0_EXCHANGE_SCOPE=openid offline_access read:private" >> .env \
16+
&& echo "API_AUTH0_AUDIENCE=http://localhost:8787/" >> .env \
17+
&& echo "API_BASE_URL=http://localhost:8787/" >> .env \
18+
&& rm auth0-app-details.json \
19+
&& echo ".env file created with your Auth0 details:" \
20+
&& cat .env
21+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
This Action is the server-side logic Auth0 executes to perform the token exchange. It is necessary because the MCP server receives an access token from the client (with the MCP server as its audience) and must exchange it for a new token (with the upstream API as the audience). This Action validates the original token and mints the new one.
2+
3+
The Custom Token Exchange Action is available as part of Custom Token Exchange Early Access. Navigate to [the On-behalf-of token exchange for first-party apps template available here](https://manage.auth0.com/#/actions/library/templates/templates/daeda4e8-8da2-4abb-afb5-ac09df0ebb2a) and click on **Use This Template**.
4+
5+
<Frame>
6+
<img
7+
src="/img/mcp/cte_action_template_page.png"
8+
alt="Action On-behalf-of token exchange for first-party apps template page"
9+
/>
10+
</Frame>
11+
12+
This will open a modal for you to name the action:
13+
14+
<Frame>
15+
<img
16+
class="img-sizing"
17+
src="/img/mcp/cte_action_creation_modal.png"
18+
alt="Action creation modal"
19+
/>
20+
</Frame>
21+
22+
Once the action is created, you can **Deploy** it. When you deploy the Action, Auth0 assigns it an Action ID. You still need to add your custom logic to the Action, but first, get the Action ID to create the Custom Token Exchange Profile.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
To call your APIs on behalf of your users, the MCP server needs to exchange the Auth0 access token it received from the MCP client (with the audience set to the MCP server itself) for a new Auth0 access token with the audience set to your API. In Auth0, this is called Custom Token Exchange and uses [RFC 8693](https://www.rfc-editor.org/rfc/rfc8693.html).
2+
3+
### The Orchestrator: `bearerForUpstream`
4+
5+
The process begins with the `bearerForUpstream` function. Its main job is to take the initial token (the `subjectToken`), manage the exchange process, and handle any potential errors gracefully.
6+
7+
This function serves as a safe wrapper around our exchange logic.
8+
9+
```javascript wrap lines highlight={5}
10+
async function bearerForUpstream(subjectToken: string) {
11+
if (!subjectToken) return { token: null, scopes: null };
12+
13+
try {
14+
const result = await exchangeCustomToken(subjectToken);
15+
return {
16+
token: result.accessToken,
17+
scopes: result.scope,
18+
}
19+
} catch (err) {
20+
console.error('Error during token exchange:', err);
21+
throw err;
22+
}
23+
}
24+
```
25+
26+
As you can see, it calls `exchangeCustomToken` and, on a successful exchange, returns the new `accessToken` and its associated scope. If the exchange fails, it logs the error and re-throws it to be handled upstream.
27+
28+
### The core logic: `exchangeCustomToken`
29+
30+
This function, located in `src/auth0.ts`, contains the actual token exchange logic. It uses the `ApiClient` from the `auth0-api-js` SDK to simplify the interaction with Auth0's `/oauth/token` endpoint.
31+
32+
First, we initialize the `ApiClient` with the credentials of the application performing the exchange:
33+
34+
```javascript wrap lines
35+
const exchangeClient = new ApiClient({
36+
domain: AUTH0_DOMAIN,
37+
audience: API_AUTH0_AUDIENCE,
38+
clientId: MCP_AUTH0_CLIENT_ID,
39+
clientSecret: MCP_AUTH0_CLIENT_SECRET,
40+
});
41+
```
42+
With the client configured, the `exchangeCustomToken` function uses the client's `getTokenByExchangeProfile` method to perform the token exchange. This method implements the [Custom Token Exchange](https://auth0.com/docs/authenticate/custom-token-exchange) flow.
43+
44+
```javascript wrap lines
45+
export async function exchangeCustomToken(subjectToken: string) {
46+
return await exchangeClient.getTokenByExchangeProfile(subjectToken, {
47+
subjectTokenType: MCP_AUTH0_SUBJECT_TOKEN_TYPE,
48+
audience: API_AUTH0_AUDIENCE,
49+
...(MCP_AUTH0_EXCHANGE_SCOPE && { scope: MCP_AUTH0_EXCHANGE_SCOPE }),
50+
});
51+
}
52+
```

0 commit comments

Comments
 (0)