Skip to content

Fix/auth0 example#617

Open
Sambego wants to merge 4 commits intoalpic-ai:mainfrom
Sambego:fix/auth0-example
Open

Fix/auth0 example#617
Sambego wants to merge 4 commits intoalpic-ai:mainfrom
Sambego:fix/auth0-example

Conversation

@Sambego
Copy link
Copy Markdown

@Sambego Sambego commented Mar 27, 2026

Fixed

  • The Auth0 example tried to get a name and email from the Access Token, but these will never be returned in an AT according to the OAuth/OpenID spec. The search-coffee-paris tool now fetches the /userinfo endpoint using the Access Token to get more user information, like email and name.
  • Rewrote Auth.js to use the @auth0/auth0-api-js package, which has a useful verifyAccessToken() method and avoids possible mistakes in trying to validate tokens.
  • Return the Access Token's client_id or azp claim as the clientId instead of the sub. Auth0 returns either a client_id or azp claim in AT, depending on which AT profile is configured.
    • client_id: the Client ID for which an access Token is issued, RFC 9068.
    • azp: Authorized party, the Client ID for which an Access Token is issued. (not standardised for Access Tokens)
    • sub: Subject, the user identifier for which an Access Token is issued.
  • Return the scopes from the Access Token instead of an empty array

Greptile Summary

This PR fixes the Auth0 example by correctly fetching user identity information from the /userinfo endpoint (rather than from Access Token claims which aren't present per the OAuth/OpenID spec), switching to @auth0/auth0-api-js for token verification, and properly mapping clientId to the client_id/azp claim and scopes to the token's scope claim.

Key changes:

  • auth.ts: Replaces manual jose-based JWT verification with ApiClient.verifyAccessToken() from @auth0/auth0-api-js. clientId is now correctly sourced from client_id/azp and scopes from the scope claim.
  • index.ts: Tool handler now calls /userinfo with the Access Token to retrieve name/email for the display name. scopes_supported metadata updated to include profile and email.
  • package.json: Adds @auth0/auth0-api-js; however the now-unused jose package was not removed.

Findings:

  • The jose dependency is no longer used after the rewrite but remains in package.json.
  • The email-based displayName fallback (email?.split("@")[0]) was dropped — userInfo.email is available from the /userinfo response and could be restored as a secondary fallback before "User".
  • scope=openid%20profile%20email is hardcoded in the authorization_endpoint URL; OAuth clients typically append their own scope parameter, which may result in duplicate scope query params with undefined precedence across implementations.

Confidence Score: 5/5

Safe to merge; all findings are minor style/cleanup items that do not affect correctness of the core auth flow.

All three issues identified are P2: an unused dependency leftover, a slightly degraded display-name fallback, and a potentially confusing (but typically harmless) double-scope URL pattern. None block functionality or introduce a security regression.

No files require special attention, though package.json should have the unused jose dependency removed for cleanliness.

Important Files Changed

Filename Overview
examples/auth-auth0/server/src/auth.ts Rewrote token verification to use @auth0/auth0-api-js ApiClient.verifyAccessToken(). Now correctly maps client_id/azp as clientId and extracts scopes from the scope claim. Error handling properly converts known Auth0 errors to InvalidTokenError and re-throws unexpected errors.
examples/auth-auth0/server/src/index.ts Tool handler now fetches /userinfo to retrieve name/email. Minor regressions: email is available from userinfo but not used as a displayName fallback; scope is hardcoded into the authorization_endpoint URL, which may produce duplicate scope params for OAuth clients.
examples/auth-auth0/package.json Added @auth0/auth0-api-js dependency. The now-unused jose package was not removed.

Comments Outside Diff (1)

  1. examples/auth-auth0/package.json, line 19 (link)

    P2 Unused jose dependency

    jose is still listed as a dependency but is no longer imported anywhere in the codebase after the rewrite to @auth0/auth0-api-js. It can be removed.

    (Delete the "jose": "^6.2.1", line entirely.)

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: examples/auth-auth0/package.json
    Line: 19
    
    Comment:
    **Unused `jose` dependency**
    
    `jose` is still listed as a dependency but is no longer imported anywhere in the codebase after the rewrite to `@auth0/auth0-api-js`. It can be removed.
    
    (Delete the `"jose": "^6.2.1",` line entirely.)
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: examples/auth-auth0/package.json
Line: 19

Comment:
**Unused `jose` dependency**

`jose` is still listed as a dependency but is no longer imported anywhere in the codebase after the rewrite to `@auth0/auth0-api-js`. It can be removed.

(Delete the `"jose": "^6.2.1",` line entirely.)

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: examples/auth-auth0/server/src/index.ts
Line: 111

Comment:
**Email fallback for `displayName` dropped**

The old code used `email?.split("@")[0]` as a secondary fallback when `name` wasn't present. Now that `userInfo` already contains `email` (since the `/userinfo` endpoint returns it for the `email` scope), the fallback can be restored without any extra requests.

```suggestion
        const displayName = userInfo?.name ?? userInfo?.email?.split("@")[0] ?? "User";
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: examples/auth-auth0/server/src/index.ts
Line: 39

Comment:
**Hardcoded `scope` in `authorization_endpoint` may conflict with client-supplied scopes**

Baking `scope=openid%20profile%20email` directly into the `authorization_endpoint` URL means that when an MCP client constructs the authorization URL, it will typically append its own `scope` parameter (per the OAuth spec), resulting in a URL with two `scope` params (e.g. `?...&scope=openid%20profile%20email&scope=openid`). RFC 6749 doesn't define behaviour for duplicate query parameters, and different implementations handle this differently.

A more standard pattern is to leave the base endpoint clean and rely on `scopes_supported` to advertise what scopes are available — the client will then request them:

```suggestion
        authorization_endpoint: `https://${env.AUTH0_DOMAIN}/authorize?audience=${encodeURIComponent(env.AUTH0_AUDIENCE)}`,
```

The `scopes_supported` metadata already advertises `["openid", "profile", "email"]`, which tells conforming clients which scopes to request.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "Cleanup" | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

(4/5) You can add custom instructions or style guidelines for the agent here!

: null;

const displayName = name ?? email?.split("@")[0] ?? "User";
const displayName = userInfo?.name ?? "User";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Email fallback for displayName dropped

The old code used email?.split("@")[0] as a secondary fallback when name wasn't present. Now that userInfo already contains email (since the /userinfo endpoint returns it for the email scope), the fallback can be restored without any extra requests.

Suggested change
const displayName = userInfo?.name ?? "User";
const displayName = userInfo?.name ?? userInfo?.email?.split("@")[0] ?? "User";
Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/auth-auth0/server/src/index.ts
Line: 111

Comment:
**Email fallback for `displayName` dropped**

The old code used `email?.split("@")[0]` as a secondary fallback when `name` wasn't present. Now that `userInfo` already contains `email` (since the `/userinfo` endpoint returns it for the `email` scope), the fallback can be restored without any extra requests.

```suggestion
        const displayName = userInfo?.name ?? userInfo?.email?.split("@")[0] ?? "User";
```

How can I resolve this? If you propose a fix, please make it concise.

oauthMetadata: {
issuer: env.SERVER_URL,
authorization_endpoint: `https://${env.AUTH0_DOMAIN}/authorize?audience=${encodeURIComponent(env.AUTH0_AUDIENCE)}`,
authorization_endpoint: `https://${env.AUTH0_DOMAIN}/authorize?audience=${encodeURIComponent(env.AUTH0_AUDIENCE)}&scope=openid%20profile%20email`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Hardcoded scope in authorization_endpoint may conflict with client-supplied scopes

Baking scope=openid%20profile%20email directly into the authorization_endpoint URL means that when an MCP client constructs the authorization URL, it will typically append its own scope parameter (per the OAuth spec), resulting in a URL with two scope params (e.g. ?...&scope=openid%20profile%20email&scope=openid). RFC 6749 doesn't define behaviour for duplicate query parameters, and different implementations handle this differently.

A more standard pattern is to leave the base endpoint clean and rely on scopes_supported to advertise what scopes are available — the client will then request them:

Suggested change
authorization_endpoint: `https://${env.AUTH0_DOMAIN}/authorize?audience=${encodeURIComponent(env.AUTH0_AUDIENCE)}&scope=openid%20profile%20email`,
authorization_endpoint: `https://${env.AUTH0_DOMAIN}/authorize?audience=${encodeURIComponent(env.AUTH0_AUDIENCE)}`,

The scopes_supported metadata already advertises ["openid", "profile", "email"], which tells conforming clients which scopes to request.

Prompt To Fix With AI
This is a comment left during a code review.
Path: examples/auth-auth0/server/src/index.ts
Line: 39

Comment:
**Hardcoded `scope` in `authorization_endpoint` may conflict with client-supplied scopes**

Baking `scope=openid%20profile%20email` directly into the `authorization_endpoint` URL means that when an MCP client constructs the authorization URL, it will typically append its own `scope` parameter (per the OAuth spec), resulting in a URL with two `scope` params (e.g. `?...&scope=openid%20profile%20email&scope=openid`). RFC 6749 doesn't define behaviour for duplicate query parameters, and different implementations handle this differently.

A more standard pattern is to leave the base endpoint clean and rely on `scopes_supported` to advertise what scopes are available — the client will then request them:

```suggestion
        authorization_endpoint: `https://${env.AUTH0_DOMAIN}/authorize?audience=${encodeURIComponent(env.AUTH0_AUDIENCE)}`,
```

The `scopes_supported` metadata already advertises `["openid", "profile", "email"]`, which tells conforming clients which scopes to request.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant