-
Notifications
You must be signed in to change notification settings - Fork 34
AIDX-319 Add python counterparts to MCP get started pages #302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c0e39f8
ee400bd
ccd1408
013a025
b748132
988a061
a7806c6
f1612d0
10717ff
5fc665b
7e165aa
d34d28e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| 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: | ||
patrickkang marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we suggest to copy the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the command we have to create
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fair enough, this particular one might not apply. But I see some other places in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed, will update that page as well
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated |
||
|
|
||
| ```shell wrap lines expandable | ||
| CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) \ | ||
| && CLIENT_SECRET=$(jq -r '.client_secret' auth0-app-details.json) \ | ||
| && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') \ | ||
| && touch .env \ | ||
| && echo "AUTH0_DOMAIN=${DOMAIN}" > .env \ | ||
| && echo "AUTH0_AUDIENCE=http://localhost:3001/" >> .env \ | ||
| && echo "PORT=3001" >> .env \ | ||
| && echo "MCP_SERVER_URL=http://localhost:3001/" >> .env \ | ||
| && echo "MCP_AUTH0_CLIENT_ID=${CLIENT_ID}" >> .env \ | ||
| && echo "MCP_AUTH0_CLIENT_SECRET=${CLIENT_SECRET}" >> .env \ | ||
| && echo "MCP_AUTH0_SUBJECT_TOKEN_TYPE=urn:fastmcp:mcp" >> .env \ | ||
| && echo "MCP_AUTH0_EXCHANGE_SCOPE=openid offline_access read:private" >> .env \ | ||
| && echo "API_AUTH0_AUDIENCE=http://localhost:8787/" >> .env \ | ||
| && echo "API_BASE_URL=http://localhost:8787/" >> .env \ | ||
| && rm auth0-app-details.json \ | ||
| && echo ".env file created with your Auth0 details:" \ | ||
| && cat .env | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| 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. | ||
|
|
||
| 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**. | ||
|
|
||
| <Frame> | ||
| <img | ||
| src="/img/mcp/cte_action_template_page.png" | ||
| alt="Action On-behalf-of token exchange for first-party apps template page" | ||
| /> | ||
| </Frame> | ||
|
|
||
| This will open a modal for you to name the action: | ||
|
|
||
| <Frame> | ||
| <img | ||
| class="img-sizing" | ||
| src="/img/mcp/cte_action_creation_modal.png" | ||
| alt="Action creation modal" | ||
| /> | ||
| </Frame> | ||
|
|
||
| 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. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| 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). | ||
|
|
||
| ### The Orchestrator: `bearerForUpstream` | ||
|
|
||
| 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. | ||
|
|
||
| This function serves as a safe wrapper around our exchange logic. | ||
|
|
||
| ```javascript wrap lines highlight={5} | ||
| async function bearerForUpstream(subjectToken: string) { | ||
| if (!subjectToken) return { token: null, scopes: null }; | ||
|
|
||
| try { | ||
| const result = await exchangeCustomToken(subjectToken); | ||
| return { | ||
| token: result.accessToken, | ||
| scopes: result.scope, | ||
| } | ||
| } catch (err) { | ||
| console.error('Error during token exchange:', err); | ||
| throw err; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| 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. | ||
|
|
||
| ### The core logic: `exchangeCustomToken` | ||
|
|
||
| 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. | ||
patrickkang marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| First, we initialize the `ApiClient` with the credentials of the application performing the exchange: | ||
|
|
||
| ```javascript wrap lines | ||
| const exchangeClient = new ApiClient({ | ||
| domain: AUTH0_DOMAIN, | ||
| audience: API_AUTH0_AUDIENCE, | ||
| clientId: MCP_AUTH0_CLIENT_ID, | ||
| clientSecret: MCP_AUTH0_CLIENT_SECRET, | ||
| }); | ||
| ``` | ||
| 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. | ||
|
|
||
| ```javascript wrap lines | ||
| export async function exchangeCustomToken(subjectToken: string) { | ||
| return await exchangeClient.getTokenByExchangeProfile(subjectToken, { | ||
| subjectTokenType: MCP_AUTH0_SUBJECT_TOKEN_TYPE, | ||
| audience: API_AUTH0_AUDIENCE, | ||
| ...(MCP_AUTH0_EXCHANGE_SCOPE && { scope: MCP_AUTH0_EXCHANGE_SCOPE }), | ||
| }); | ||
| } | ||
| ``` | ||
Uh oh!
There was an error while loading. Please reload this page.