feat: send the MetaMask auth token to built-in Infura endpoints - #9927
feat: send the MetaMask auth token to built-in Infura endpoints#9927basgys wants to merge 1 commit into
Conversation
0905232 to
ad065ed
Compare
ad065ed to
9272c5d
Compare
`NetworkController` gains an optional `getInfuraAuthToken` option. It is called once per request to the primary endpoint of a network client of type `infura` (the ones built from `infuraProjectId`), and the token it returns is sent as a bearer credential in the `Authorization` header alongside the v3 project ID in the URL. Custom endpoints and failover endpoints never carry the token, so a user-supplied Infura key is never paired with it. When the token is unavailable or retrieval throws, the request is made unauthenticated. `@metamask/wallet` wires the option to `AuthenticationController:getBearerToken` over the network controller messenger, and only while `AnalyticsController` state has `optedIn: true`, since the token identifies the user.
9272c5d to
ef7260c
Compare
| analyticsOptions: options.analyticsOptions, | ||
| // The token identifies the user, which is only allowed for analytics | ||
| // opt-ins. | ||
| getInfuraAuthToken: async () => |
There was a problem hiding this comment.
Thoughts on moving this inside of the NetworkController, rather than passing it in as a constructor parameter?
For context, our intention with the messenger is to use it for all communication between wallet components, reserving constructor parameters just for platform dependencies that haven't been migrated to a service yet. Eventually we hope to eliminate all (or nearly all) constructor parameters in favor of messenger actions/events.
Also, the messenger is meant to represent the full set of wallet capabilities that a particular component has. This strategy of extending the capabilities of the messenger just for initialization creates a misleading perception of the capabilities of the NetworkController (it will appear to not have the AuthenticationController:getBearerToken capability, but in reality it will), which is definitely not something we want.
Explanation
Infura accepts the MetaMask auth token as
Authorization: Beareralongside the v3 project ID in the URL. This adds an optionalgetInfuraAuthTokenoption toNetworkControllerand wires it in@metamask/wallettoAuthenticationController:getBearerToken, gated on analytics opt-in.Built-in Infura endpoints only. The token goes on the primary endpoint of
infura-type network clients, the ones built frominfuraProjectId. Custom endpoints never carry it, even on aninfura.iohost: that is someone else's key. Failover endpoints never carry it: other providers. The gate is client type plus position in the chain, not URL matching, sorpcFailoverMode: 'forced'sends the token nowhere.Read per request. A refreshed token is used on the next request. If the function returns
undefinedor throws, the request is made without the header. In the wallet that covers the locked state (getBearerTokenthrows until unlock) and clients that do not registerAuthenticationController, such aswallet-cli.Analytics opt-in only. The token identifies the user, which is only allowed for analytics opt-ins. The wallet returns it only while
AnalyticsControllerstate hasoptedIn: true, otherwiseundefined.NetworkControllerstays policy-free: the option is the seam, and clients that construct the controller directly own the gate in their owngetInfuraAuthToken.Wallet wiring.
AuthenticationController:getBearerTokenis delegated to the network controller messenger, as it already is forShieldApiService,ClaimsService, andSubscriptionService, and passed throughgetInfuraAuthToken.AnalyticsController:getStatewas already delegated. No new instance option.@metamask/profile-sync-controlleris added as a dependency for the action type.Not supported: Infura-issued JWTs. Same header, mutually exclusive. MetaMask clients use v3 keys and the UI has no JWT input.
Open question: the extension's
FEATURED_RPCSnetworks (Linea, Base, ...) areRpcEndpointType.Customwith our project ID, so the type gate excludes them. Include them by also matching/v3/<infuraProjectId>, or keep the type gate?References
None.
Checklist
Note
Medium Risk
Changes outbound RPC auth on default Infura traffic and ties it to analytics opt-in and bearer retrieval; mis-gating could leak identifiers or break RPC when tokens fail.
Overview
Adds optional
getInfuraAuthTokenonNetworkController, threaded through auto-managed network clients into RPCfetch. AwithInfuraAuthTokenwrapper setsAuthorization: Bearer …once per request; missing or failed token lookup still sends the RPC without the header.The credential applies only to the primary endpoint of
infura-type clients (built frominfuraProjectId), not custom RPC URLs or failover endpoints—even on Infura hosts—so user keys are never paired with the MetaMask token.@metamask/walletwires the hook toAuthenticationController:getBearerTokenwhenAnalyticsControllerreportsoptedIn, delegates that action on the network messenger, and adds@metamask/profile-sync-controllerfor the action type. Tests cover bearer behavior, per-request refresh, endpoint scoping, and wallet opt-in gating.Reviewed by Cursor Bugbot for commit ef7260c. Bugbot is set up for automated code reviews on this repo. Configure here.