@metamask-previews/profile-sync-controller 28.0.2-preview-8e9c439 → 28.0.2-preview-4845f8918

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/controllers/authentication/AuthenticationController-method-action-types.cjs.map +1 -1
  3. package/dist/controllers/authentication/AuthenticationController-method-action-types.d.cts +8 -3
  4. package/dist/controllers/authentication/AuthenticationController-method-action-types.d.cts.map +1 -1
  5. package/dist/controllers/authentication/AuthenticationController-method-action-types.d.mts +8 -3
  6. package/dist/controllers/authentication/AuthenticationController-method-action-types.d.mts.map +1 -1
  7. package/dist/controllers/authentication/AuthenticationController-method-action-types.mjs.map +1 -1
  8. package/dist/controllers/authentication/AuthenticationController.cjs +58 -4
  9. package/dist/controllers/authentication/AuthenticationController.cjs.map +1 -1
  10. package/dist/controllers/authentication/AuthenticationController.d.cts +19 -5
  11. package/dist/controllers/authentication/AuthenticationController.d.cts.map +1 -1
  12. package/dist/controllers/authentication/AuthenticationController.d.mts +19 -5
  13. package/dist/controllers/authentication/AuthenticationController.d.mts.map +1 -1
  14. package/dist/controllers/authentication/AuthenticationController.mjs +58 -4
  15. package/dist/controllers/authentication/AuthenticationController.mjs.map +1 -1
  16. package/dist/controllers/authentication/mocks/mockResponses.d.cts +18 -0
  17. package/dist/controllers/authentication/mocks/mockResponses.d.cts.map +1 -1
  18. package/dist/controllers/authentication/mocks/mockResponses.d.mts +18 -0
  19. package/dist/controllers/authentication/mocks/mockResponses.d.mts.map +1 -1
  20. package/dist/sdk/authentication-jwt-bearer/flow-srp.cjs +18 -1
  21. package/dist/sdk/authentication-jwt-bearer/flow-srp.cjs.map +1 -1
  22. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.cts +2 -0
  23. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.cts.map +1 -1
  24. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.mts +2 -0
  25. package/dist/sdk/authentication-jwt-bearer/flow-srp.d.mts.map +1 -1
  26. package/dist/sdk/authentication-jwt-bearer/flow-srp.mjs +19 -2
  27. package/dist/sdk/authentication-jwt-bearer/flow-srp.mjs.map +1 -1
  28. package/dist/sdk/authentication-jwt-bearer/services.cjs +56 -1
  29. package/dist/sdk/authentication-jwt-bearer/services.cjs.map +1 -1
  30. package/dist/sdk/authentication-jwt-bearer/services.d.cts +17 -1
  31. package/dist/sdk/authentication-jwt-bearer/services.d.cts.map +1 -1
  32. package/dist/sdk/authentication-jwt-bearer/services.d.mts +17 -1
  33. package/dist/sdk/authentication-jwt-bearer/services.d.mts.map +1 -1
  34. package/dist/sdk/authentication-jwt-bearer/services.mjs +53 -0
  35. package/dist/sdk/authentication-jwt-bearer/services.mjs.map +1 -1
  36. package/dist/sdk/authentication-jwt-bearer/types.cjs.map +1 -1
  37. package/dist/sdk/authentication-jwt-bearer/types.d.cts +20 -1
  38. package/dist/sdk/authentication-jwt-bearer/types.d.cts.map +1 -1
  39. package/dist/sdk/authentication-jwt-bearer/types.d.mts +20 -1
  40. package/dist/sdk/authentication-jwt-bearer/types.d.mts.map +1 -1
  41. package/dist/sdk/authentication-jwt-bearer/types.mjs.map +1 -1
  42. package/dist/sdk/authentication-jwt-bearer/utils/identifier.cjs +27 -0
  43. package/dist/sdk/authentication-jwt-bearer/utils/identifier.cjs.map +1 -0
  44. package/dist/sdk/authentication-jwt-bearer/utils/identifier.d.cts +13 -0
  45. package/dist/sdk/authentication-jwt-bearer/utils/identifier.d.cts.map +1 -0
  46. package/dist/sdk/authentication-jwt-bearer/utils/identifier.d.mts +13 -0
  47. package/dist/sdk/authentication-jwt-bearer/utils/identifier.d.mts.map +1 -0
  48. package/dist/sdk/authentication-jwt-bearer/utils/identifier.mjs +23 -0
  49. package/dist/sdk/authentication-jwt-bearer/utils/identifier.mjs.map +1 -0
  50. package/dist/sdk/authentication.cjs +4 -0
  51. package/dist/sdk/authentication.cjs.map +1 -1
  52. package/dist/sdk/authentication.d.cts +2 -0
  53. package/dist/sdk/authentication.d.cts.map +1 -1
  54. package/dist/sdk/authentication.d.mts +2 -0
  55. package/dist/sdk/authentication.d.mts.map +1 -1
  56. package/dist/sdk/authentication.mjs +4 -0
  57. package/dist/sdk/authentication.mjs.map +1 -1
  58. package/dist/sdk/mocks/auth.cjs +11 -1
  59. package/dist/sdk/mocks/auth.cjs.map +1 -1
  60. package/dist/sdk/mocks/auth.d.cts +10 -0
  61. package/dist/sdk/mocks/auth.d.cts.map +1 -1
  62. package/dist/sdk/mocks/auth.d.mts +10 -0
  63. package/dist/sdk/mocks/auth.d.mts.map +1 -1
  64. package/dist/sdk/mocks/auth.mjs +11 -1
  65. package/dist/sdk/mocks/auth.mjs.map +1 -1
  66. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"AuthenticationController.mjs","sourceRoot":"","sources":["../../../src/controllers/authentication/AuthenticationController.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAqB3D,OAAO,EACL,+BAA+B,EAC/B,QAAQ,EACR,GAAG,EACH,aAAa,EACd,4BAAkB;AAEnB,OAAO,EACL,0BAA0B,EAC1B,8BAA8B,EAC9B,4BAA4B,EAC7B,iCAA6B;AAG9B,MAAM,cAAc,GAAG,0BAA0B,CAAC;AAOlD,MAAM,CAAC,MAAM,YAAY,GAAkC;IACzD,UAAU,EAAE,KAAK;CAClB,CAAC;AACF,MAAM,QAAQ,GAAiD;IAC7D,UAAU,EAAE;QACV,kBAAkB,EAAE,IAAI;QACxB,OAAO,EAAE,IAAI;QACb,sBAAsB,EAAE,IAAI;QAC5B,QAAQ,EAAE,IAAI;KACf;IACD,cAAc,EAAE;QACd,sCAAsC;QACtC,kBAAkB,EAAE,CAAC,cAAc,EAAE,EAAE;YACrC,4FAA4F;YAC5F,2FAA2F;YAC3F,mEAAmE;YACnE,kEAAkE;YAClE,oDAAoD;YACpD,IAAI,cAAc,KAAK,IAAI,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;gBAC5D,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,MAAM,CAC1C,CAAC,uBAAuB,EAAE,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE;gBACxC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,uBAAuB,EAAE,GACxD,KAAK,CAAC,KAAK,CAAC;gBACd,uBAAuB,CAAC,GAAG,CAAC,GAAG;oBAC7B,GAAG,KAAK;oBACR,KAAK,EAAE,uBAAuB;iBAC/B,CAAC;gBACF,OAAO,uBAAuB,CAAC;YACjC,CAAC,EACD,EAAE,CACH,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,IAAI;QACb,sBAAsB,EAAE,KAAK;QAC7B,QAAQ,EAAE,IAAI;KACf;CACF,CAAC;AAMF,MAAM,yBAAyB,GAAG;IAChC,eAAe;IACf,gBAAgB;IAChB,gBAAgB;IAChB,mBAAmB;IACnB,uBAAuB;IACvB,YAAY;CACJ,CAAC;AAiCX;;;GAGG;AACH,MAAM,OAAO,wBAAyB,SAAQ,cAI7C;IA4BC,YAAY,EACV,SAAS,EACT,KAAK,EACL,MAAM,EACN,WAAW,GAUZ;QACC,KAAK,CAAC;YACJ,SAAS;YACT,QAAQ;YACR,IAAI,EAAE,cAAc;YACpB,KAAK,EAAE,EAAE,GAAG,YAAY,EAAE,GAAG,KAAK,EAAE;SACrC,CAAC,CAAC;;QA/CI,wDAA8B;QAE9B,iDAAoB;QAEpB,2CAA4B;YACnC,GAAG,EAAE,GAAG,CAAC,GAAG;SACb,EAAC;QAEF,+CAAc,KAAK,EAAC;QAEpB,yEAAuC;QAE9B,sDAAqB;YAC5B,6BAA6B,EAAE,GAAG,EAAE;gBAClC,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;gBACzE,uBAAA,IAAI,wCAAe,UAAU,MAAA,CAAC;gBAE9B,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,0BAA0B,EAAE,GAAG,EAAE;oBACxD,uBAAA,IAAI,wCAAe,IAAI,MAAA,CAAC;gBAC1B,CAAC,CAAC,CAAC;gBAEH,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,wBAAwB,EAAE,GAAG,EAAE;oBACtD,uBAAA,IAAI,wCAAe,KAAK,MAAA,CAAC;gBAC3B,CAAC,CAAC,CAAC;YACL,CAAC;SACF,EAAC;QAkOF,0DAA+D,EAAE,EAAC;QA1MhE,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;QACrD,CAAC;QAED,uBAAA,IAAI,oCAAW;YACb,GAAG,uBAAA,IAAI,wCAAQ;YACf,GAAG,MAAM;SACV,MAAA,CAAC;QAEF,uBAAA,IAAI,yCAAgB,WAAW,MAAA,CAAC;QAEhC,uBAAA,IAAI,kCAAS,IAAI,aAAa,CAC5B;YACE,GAAG,EAAE,uBAAA,IAAI,wCAAQ,CAAC,GAAG;YACrB,QAAQ,EAAE,WAAW,CAAC,KAAK;YAC3B,IAAI,EAAE,QAAQ,CAAC,GAAG;SACnB,EACD;YACE,OAAO,EAAE;gBACP,gBAAgB,EAAE,uBAAA,IAAI,gGAA2B,CAAC,IAAI,CAAC,IAAI,CAAC;gBAC5D,gBAAgB,EAAE,uBAAA,IAAI,8FAAyB,CAAC,IAAI,CAAC,IAAI,CAAC;aAC3D;YACD,OAAO,EAAE;gBACP,aAAa,EAAE,uBAAA,IAAI,uFAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;gBAChD,WAAW,EAAE,uBAAA,IAAI,sFAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;aAC9C;YACD,WAAW,EAAE,uBAAA,IAAI,6CAAa;SAC/B,CACF,MAAA,CAAC;QAEF,uBAAA,IAAI,mDAAmB,CAAC,6BAA6B,EAAE,CAAC;QAExD,IAAI,CAAC,SAAS,CAAC,4BAA4B,CACzC,IAAI,EACJ,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IAgEM,KAAK,CAAC,aAAa;QACxB,uBAAA,IAAI,uFAAkB,MAAtB,IAAI,EAAmB,eAAe,CAAC,CAAC;QAExC,MAAM,aAAa,GAAG,MAAM,uBAAA,IAAI,2FAAsB,MAA1B,IAAI,CAAwB,CAAC;QACzD,MAAM,YAAY,GAAG,EAAE,CAAC;QAExB,mEAAmE;QACnE,oCAAoC;QACpC,KAAK,MAAM,CAAC,eAAe,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9C,MAAM,WAAW,GAAG,MAAM,uBAAA,IAAI,sCAAM,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;YACrE,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC;QAED,OAAO,YAAY,CAAC;IACtB,CAAC;IAEM,cAAc;QACnB,uBAAA,IAAI,0DAAiC,SAAS,MAAA,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;YACpB,KAAK,CAAC,UAAU,GAAG,KAAK,CAAC;YACzB,KAAK,CAAC,cAAc,GAAG,SAAS,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IAEI,KAAK,CAAC,cAAc,CAAC,eAAwB;QAClD,uBAAA,IAAI,uFAAkB,MAAtB,IAAI,EAAmB,gBAAgB,CAAC,CAAC;QACzC,MAAM,UAAU,GACd,eAAe,IAAI,CAAC,MAAM,uBAAA,IAAI,gGAA2B,MAA/B,IAAI,CAA6B,CAAC,CAAC;QAC/D,OAAO,MAAM,uBAAA,IAAI,sCAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IACrD,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,iBAAiB,CAC5B,eAAwB;QAExB,uBAAA,IAAI,uFAAkB,MAAtB,IAAI,EAAmB,mBAAmB,CAAC,CAAC;QAC5C,MAAM,UAAU,GACd,eAAe,IAAI,CAAC,MAAM,uBAAA,IAAI,gGAA2B,MAA/B,IAAI,CAA6B,CAAC,CAAC;QAC/D,OAAO,MAAM,uBAAA,IAAI,sCAAM,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;IACrD,CAAC;IAEM,KAAK,CAAC,qBAAqB,CAChC,eAAwB;QAExB,uBAAA,IAAI,uFAAkB,MAAtB,IAAI,EAAmB,uBAAuB,CAAC,CAAC;QAChD,MAAM,UAAU,GACd,eAAe,IAAI,CAAC,MAAM,uBAAA,IAAI,gGAA2B,MAA/B,IAAI,CAA6B,CAAC,CAAC;QAC/D,OAAO,MAAM,uBAAA,IAAI,sCAAM,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC5D,CAAC;IAEM,UAAU;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;IAC/B,CAAC;CAmEF;ggBAnMC,KAAK,8DACH,eAAwB;IAExB,MAAM,UAAU,GACd,eAAe,IAAI,CAAC,MAAM,uBAAA,IAAI,gGAA2B,MAA/B,IAAI,CAA6B,CAAC,CAAC;IAC/D,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;QAC7C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;AAC/C,CAAC,sDAED,KAAK,4DACH,aAA4B,EAC5B,eAAwB;IAExB,MAAM,UAAU,GACd,eAAe,IAAI,CAAC,MAAM,uBAAA,IAAI,gGAA2B,MAA/B,IAAI,CAA6B,CAAC,CAAC;IAC/D,MAAM,aAAa,GAAG,MAAM,uBAAA,IAAI,6CAAa,CAAC,gBAAgB,EAAE,CAAC;IACjE,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE;QACpB,KAAK,CAAC,UAAU,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,CAAC;YAC1B,KAAK,CAAC,cAAc,GAAG,EAAE,CAAC;QAC5B,CAAC;QACD,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,GAAG;YACjC,GAAG,aAAa;YAChB,OAAO,EAAE;gBACP,GAAG,aAAa,CAAC,OAAO;gBACxB,aAAa;aACd;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,mGAEiB,UAAkB;IAClC,IAAI,CAAC,uBAAA,IAAI,4CAAY,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,wCAAwC,CAAC,CAAC;IACzE,CAAC;AACH,CAAC,wDAED,KAAK;IACH,IAAI,uBAAA,IAAI,8DAA8B,EAAE,CAAC;QACvC,OAAO,uBAAA,IAAI,8DAA8B,CAAC;IAC5C,CAAC;IACD,MAAM,aAAa,GAAG,MAAM,uBAAA,IAAI,2FAAsB,MAA1B,IAAI,CAAwB,CAAC;IAEzD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CACb,iEAAiE,CAClE,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,qEAAqE,CACtE,CAAC;IACJ,CAAC;IAED,uBAAA,IAAI,0DAAiC,SAAS,MAAA,CAAC;IAC/C,OAAO,uBAAA,IAAI,8DAA8B,CAAC;AAC5C,CAAC;AAsED;;;;;;GAMG;AACH,KAAK,qDAAmB,eAAwB;IAC9C,uBAAA,IAAI,uFAAkB,MAAtB,IAAI,EAAmB,mBAAmB,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACvC,8BAA8B,EAC9B,0BAA0B,CAAC,eAAe,CAAC,CAC5C,CAAW,CAAC;IAEb,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,KAAK;IACH,uBAAA,IAAI,uFAAkB,MAAtB,IAAI,EAAmB,uBAAuB,CAAC,CAAC;IAEhD,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACvC,8BAA8B,EAC9B,8BAA8B,EAAE,CACjC,CAAuB,CAAC;IAEzB,OAAO,MAAM,CAAC;AAChB,CAAC;AAID;;;;;;;GAOG;AACH,KAAK,oDACH,OAAe,EACf,eAAwB;IAExB,+BAA+B,CAAC,OAAO,CAAC,CAAC;IAEzC,IAAI,uBAAA,IAAI,uDAAuB,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,OAAO,uBAAA,IAAI,uDAAuB,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC;IAED,uBAAA,IAAI,uFAAkB,MAAtB,IAAI,EAAmB,kBAAkB,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CACvC,8BAA8B,EAC9B,4BAA4B,CAAC,OAAO,EAAE,eAAe,CAAC,CACvD,CAAW,CAAC;IAEb,uBAAA,IAAI,uDAAuB,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC;IAE9C,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { SnapControllerHandleRequestAction } from '@metamask/snaps-controllers';\nimport type { Json } from '@metamask/utils';\n\nimport type {\n LoginResponse,\n SRPInterface,\n UserProfile,\n UserProfileLineage,\n} from '../../sdk';\nimport {\n assertMessageStartsWithMetamask,\n AuthType,\n Env,\n JwtBearerAuth,\n} from '../../sdk';\nimport type { MetaMetricsAuth } from '../../shared/types/services';\nimport {\n createSnapPublicKeyRequest,\n createSnapAllPublicKeysRequest,\n createSnapSignMessageRequest,\n} from './auth-snap-requests';\nimport { AuthenticationControllerMethodActions } from './AuthenticationController-method-action-types';\n\nconst controllerName = 'AuthenticationController';\n\n// State\nexport type AuthenticationControllerState = {\n isSignedIn: boolean;\n srpSessionData?: Record<string, LoginResponse>;\n};\nexport const defaultState: AuthenticationControllerState = {\n isSignedIn: false,\n};\nconst metadata: StateMetadata<AuthenticationControllerState> = {\n isSignedIn: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n srpSessionData: {\n // Remove access token from state logs\n includeInStateLogs: (srpSessionData) => {\n // Unreachable branch, included just to fix a type error for the case where this property is\n // unset. The type gets collapsed to include `| undefined` even though `undefined` is never\n // set here, because we don't yet use `exactOptionalPropertyTypes`.\n // TODO: Remove branch after enabling `exactOptionalPropertyTypes`\n // ref: https://github.com/MetaMask/core/issues/6565\n if (srpSessionData === null || srpSessionData === undefined) {\n return null;\n }\n return Object.entries(srpSessionData).reduce<Record<string, Json>>(\n (sanitizedSrpSessionData, [key, value]) => {\n const { accessToken: _unused, ...tokenWithoutAccessToken } =\n value.token;\n sanitizedSrpSessionData[key] = {\n ...value,\n token: tokenWithoutAccessToken,\n };\n return sanitizedSrpSessionData;\n },\n {},\n );\n },\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n};\n\ntype ControllerConfig = {\n env: Env;\n};\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'performSignIn',\n 'performSignOut',\n 'getBearerToken',\n 'getSessionProfile',\n 'getUserProfileLineage',\n 'isSignedIn',\n] as const;\n\nexport type Actions =\n | AuthenticationControllerGetStateAction\n | AuthenticationControllerMethodActions;\n\nexport type AuthenticationControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AuthenticationControllerState\n>;\n\nexport type AuthenticationControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n AuthenticationControllerState\n >;\n\nexport type Events = AuthenticationControllerStateChangeEvent;\n\n// Allowed Actions\ntype AllowedActions =\n | KeyringControllerGetStateAction\n | SnapControllerHandleRequestAction;\n\ntype AllowedEvents = KeyringControllerLockEvent | KeyringControllerUnlockEvent;\n\n// Messenger\nexport type AuthenticationControllerMessenger = Messenger<\n typeof controllerName,\n Actions | AllowedActions,\n Events | AllowedEvents\n>;\n\n/**\n * Controller that enables authentication for restricted endpoints.\n * Used for Backup & Sync, Notifications, and other services.\n */\nexport class AuthenticationController extends BaseController<\n typeof controllerName,\n AuthenticationControllerState,\n AuthenticationControllerMessenger\n> {\n readonly #metametrics: MetaMetricsAuth;\n\n readonly #auth: SRPInterface;\n\n readonly #config: ControllerConfig = {\n env: Env.PRD,\n };\n\n #isUnlocked = false;\n\n #cachedPrimaryEntropySourceId?: string;\n\n readonly #keyringController = {\n setupLockedStateSubscriptions: () => {\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n this.#isUnlocked = isUnlocked;\n\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n });\n\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n });\n },\n };\n\n constructor({\n messenger,\n state,\n config,\n metametrics,\n }: {\n messenger: AuthenticationControllerMessenger;\n state?: AuthenticationControllerState;\n config?: Partial<ControllerConfig>;\n /**\n * Not using the Messaging System as we\n * do not want to tie this strictly to extension\n */\n metametrics: MetaMetricsAuth;\n }) {\n super({\n messenger,\n metadata,\n name: controllerName,\n state: { ...defaultState, ...state },\n });\n\n if (!metametrics) {\n throw new Error('`metametrics` field is required');\n }\n\n this.#config = {\n ...this.#config,\n ...config,\n };\n\n this.#metametrics = metametrics;\n\n this.#auth = new JwtBearerAuth(\n {\n env: this.#config.env,\n platform: metametrics.agent,\n type: AuthType.SRP,\n },\n {\n storage: {\n getLoginResponse: this.#getLoginResponseFromState.bind(this),\n setLoginResponse: this.#setLoginResponseToState.bind(this),\n },\n signing: {\n getIdentifier: this.#snapGetPublicKey.bind(this),\n signMessage: this.#snapSignMessage.bind(this),\n },\n metametrics: this.#metametrics,\n },\n );\n\n this.#keyringController.setupLockedStateSubscriptions();\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n async #getLoginResponseFromState(\n entropySourceId?: string,\n ): Promise<LoginResponse | null> {\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n if (!this.state.srpSessionData?.[resolvedId]) {\n return null;\n }\n return this.state.srpSessionData[resolvedId];\n }\n\n async #setLoginResponseToState(\n loginResponse: LoginResponse,\n entropySourceId?: string,\n ) {\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n const metaMetricsId = await this.#metametrics.getMetaMetricsId();\n this.update((state) => {\n state.isSignedIn = true;\n if (!state.srpSessionData) {\n state.srpSessionData = {};\n }\n state.srpSessionData[resolvedId] = {\n ...loginResponse,\n profile: {\n ...loginResponse.profile,\n metaMetricsId,\n },\n };\n });\n }\n\n #assertIsUnlocked(methodName: string): void {\n if (!this.#isUnlocked) {\n throw new Error(`${methodName} - unable to proceed, wallet is locked`);\n }\n }\n\n async #getPrimaryEntropySourceId(): Promise<string> {\n if (this.#cachedPrimaryEntropySourceId) {\n return this.#cachedPrimaryEntropySourceId;\n }\n const allPublicKeys = await this.#snapGetAllPublicKeys();\n\n if (allPublicKeys.length === 0) {\n throw new Error(\n '#getPrimaryEntropySourceId - No entropy sources found from snap',\n );\n }\n\n const primaryId = allPublicKeys[0][0];\n if (!primaryId) {\n throw new Error(\n '#getPrimaryEntropySourceId - Primary entropy source ID is undefined',\n );\n }\n\n this.#cachedPrimaryEntropySourceId = primaryId;\n return this.#cachedPrimaryEntropySourceId;\n }\n\n public async performSignIn(): Promise<string[]> {\n this.#assertIsUnlocked('performSignIn');\n\n const allPublicKeys = await this.#snapGetAllPublicKeys();\n const accessTokens = [];\n\n // We iterate sequentially in order to be sure that the first entry\n // is the primary SRP LoginResponse.\n for (const [entropySourceId] of allPublicKeys) {\n const accessToken = await this.#auth.getAccessToken(entropySourceId);\n accessTokens.push(accessToken);\n }\n\n return accessTokens;\n }\n\n public performSignOut(): void {\n this.#cachedPrimaryEntropySourceId = undefined;\n this.update((state) => {\n state.isSignedIn = false;\n state.srpSessionData = undefined;\n });\n }\n\n /**\n * Will return a bearer token.\n * Logs a user in if a user is not logged in.\n *\n * @returns profile for the session.\n */\n\n public async getBearerToken(entropySourceId?: string): Promise<string> {\n this.#assertIsUnlocked('getBearerToken');\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n return await this.#auth.getAccessToken(resolvedId);\n }\n\n /**\n * Will return a session profile.\n * Logs a user in if a user is not logged in.\n *\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n * @returns profile for the session.\n */\n public async getSessionProfile(\n entropySourceId?: string,\n ): Promise<UserProfile> {\n this.#assertIsUnlocked('getSessionProfile');\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n return await this.#auth.getUserProfile(resolvedId);\n }\n\n public async getUserProfileLineage(\n entropySourceId?: string,\n ): Promise<UserProfileLineage> {\n this.#assertIsUnlocked('getUserProfileLineage');\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n return await this.#auth.getUserProfileLineage(resolvedId);\n }\n\n public isSignedIn(): boolean {\n return this.state.isSignedIn;\n }\n\n /**\n * Returns the auth snap public key.\n *\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n * @returns The snap public key.\n */\n async #snapGetPublicKey(entropySourceId?: string): Promise<string> {\n this.#assertIsUnlocked('#snapGetPublicKey');\n\n const result = (await this.messenger.call(\n 'SnapController:handleRequest',\n createSnapPublicKeyRequest(entropySourceId),\n )) as string;\n\n return result;\n }\n\n /**\n * Returns a mapping of entropy source IDs to auth snap public keys.\n *\n * @returns A mapping of entropy source IDs to public keys.\n */\n async #snapGetAllPublicKeys(): Promise<[string, string][]> {\n this.#assertIsUnlocked('#snapGetAllPublicKeys');\n\n const result = (await this.messenger.call(\n 'SnapController:handleRequest',\n createSnapAllPublicKeysRequest(),\n )) as [string, string][];\n\n return result;\n }\n\n #_snapSignMessageCache: Record<`metamask:${string}`, string> = {};\n\n /**\n * Signs a specific message using an underlying auth snap.\n *\n * @param message - A specific tagged message to sign.\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n * @returns A Signature created by the snap.\n */\n async #snapSignMessage(\n message: string,\n entropySourceId?: string,\n ): Promise<string> {\n assertMessageStartsWithMetamask(message);\n\n if (this.#_snapSignMessageCache[message]) {\n return this.#_snapSignMessageCache[message];\n }\n\n this.#assertIsUnlocked('#snapSignMessage');\n\n const result = (await this.messenger.call(\n 'SnapController:handleRequest',\n createSnapSignMessageRequest(message, entropySourceId),\n )) as string;\n\n this.#_snapSignMessageCache[message] = result;\n\n return result;\n }\n}\n"]}
1
+ {"version":3,"file":"AuthenticationController.mjs","sourceRoot":"","sources":["../../../src/controllers/authentication/AuthenticationController.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseController } from '@metamask/base-controller';\nimport type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport type {\n KeyringControllerGetStateAction,\n KeyringControllerLockEvent,\n KeyringControllerUnlockEvent,\n} from '@metamask/keyring-controller';\nimport type { Messenger } from '@metamask/messenger';\nimport type { SnapControllerHandleRequestAction } from '@metamask/snaps-controllers';\nimport type { Json } from '@metamask/utils';\n\nimport type {\n LoginResponse,\n ProfileAlias,\n SRPInterface,\n UserProfile,\n UserProfileLineage,\n} from '../../sdk';\nimport {\n assertMessageStartsWithMetamask,\n AuthType,\n Env,\n JwtBearerAuth,\n} from '../../sdk';\nimport type { MetaMetricsAuth } from '../../shared/types/services';\nimport {\n createSnapPublicKeyRequest,\n createSnapAllPublicKeysRequest,\n createSnapSignMessageRequest,\n} from './auth-snap-requests';\nimport { AuthenticationControllerMethodActions } from './AuthenticationController-method-action-types';\n\nconst controllerName = 'AuthenticationController';\n\n// State\nexport type AuthenticationControllerState = {\n isSignedIn: boolean;\n srpSessionData?: Record<string, LoginResponse>;\n};\nexport const defaultState: AuthenticationControllerState = {\n isSignedIn: false,\n};\nconst metadata: StateMetadata<AuthenticationControllerState> = {\n isSignedIn: {\n includeInStateLogs: true,\n persist: true,\n includeInDebugSnapshot: true,\n usedInUi: true,\n },\n srpSessionData: {\n // Remove access token from state logs\n includeInStateLogs: (srpSessionData) => {\n // Unreachable branch, included just to fix a type error for the case where this property is\n // unset. The type gets collapsed to include `| undefined` even though `undefined` is never\n // set here, because we don't yet use `exactOptionalPropertyTypes`.\n // TODO: Remove branch after enabling `exactOptionalPropertyTypes`\n // ref: https://github.com/MetaMask/core/issues/6565\n if (srpSessionData === null || srpSessionData === undefined) {\n return null;\n }\n return Object.entries(srpSessionData).reduce<Record<string, Json>>(\n (sanitizedSrpSessionData, [key, value]) => {\n const { accessToken: _unused, ...tokenWithoutAccessToken } =\n value.token;\n sanitizedSrpSessionData[key] = {\n ...value,\n token: tokenWithoutAccessToken,\n };\n return sanitizedSrpSessionData;\n },\n {},\n );\n },\n persist: true,\n includeInDebugSnapshot: false,\n usedInUi: true,\n },\n};\n\ntype ControllerConfig = {\n env: Env;\n};\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'performSignIn',\n 'performSignOut',\n 'getBearerToken',\n 'getSessionProfile',\n 'getUserProfileLineage',\n 'isSignedIn',\n] as const;\n\nexport type Actions =\n | AuthenticationControllerGetStateAction\n | AuthenticationControllerMethodActions;\n\nexport type AuthenticationControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n AuthenticationControllerState\n>;\n\nexport type AuthenticationControllerStateChangeEvent =\n ControllerStateChangeEvent<\n typeof controllerName,\n AuthenticationControllerState\n >;\n\nexport type ProfileSignInInfo = {\n profileId: string;\n profileAliases: ProfileAlias[];\n profileIdChanged: boolean;\n};\n\nexport type AuthenticationControllerProfileSignInEvent = {\n type: `${typeof controllerName}:profileSignIn`;\n payload: [ProfileSignInInfo];\n};\n\nexport type Events =\n | AuthenticationControllerStateChangeEvent\n | AuthenticationControllerProfileSignInEvent;\n\n// Allowed Actions\ntype AllowedActions =\n | KeyringControllerGetStateAction\n | SnapControllerHandleRequestAction;\n\ntype AllowedEvents = KeyringControllerLockEvent | KeyringControllerUnlockEvent;\n\n// Messenger\nexport type AuthenticationControllerMessenger = Messenger<\n typeof controllerName,\n Actions | AllowedActions,\n Events | AllowedEvents\n>;\n\n/**\n * Controller that enables authentication for restricted endpoints.\n * Used for Backup & Sync, Notifications, and other services.\n */\nexport class AuthenticationController extends BaseController<\n typeof controllerName,\n AuthenticationControllerState,\n AuthenticationControllerMessenger\n> {\n readonly #metametrics: MetaMetricsAuth;\n\n readonly #auth: SRPInterface;\n\n readonly #config: ControllerConfig = {\n env: Env.PRD,\n };\n\n #isUnlocked = false;\n\n #cachedPrimaryEntropySourceId?: string;\n\n readonly #keyringController = {\n setupLockedStateSubscriptions: () => {\n const { isUnlocked } = this.messenger.call('KeyringController:getState');\n this.#isUnlocked = isUnlocked;\n\n this.messenger.subscribe('KeyringController:unlock', () => {\n this.#isUnlocked = true;\n });\n\n this.messenger.subscribe('KeyringController:lock', () => {\n this.#isUnlocked = false;\n });\n },\n };\n\n constructor({\n messenger,\n state,\n config,\n metametrics,\n }: {\n messenger: AuthenticationControllerMessenger;\n state?: AuthenticationControllerState;\n config?: Partial<ControllerConfig>;\n /**\n * Not using the Messaging System as we\n * do not want to tie this strictly to extension\n */\n metametrics: MetaMetricsAuth;\n }) {\n super({\n messenger,\n metadata,\n name: controllerName,\n state: { ...defaultState, ...state },\n });\n\n if (!metametrics) {\n throw new Error('`metametrics` field is required');\n }\n\n this.#config = {\n ...this.#config,\n ...config,\n };\n\n this.#metametrics = metametrics;\n\n this.#auth = new JwtBearerAuth(\n {\n env: this.#config.env,\n platform: metametrics.agent,\n type: AuthType.SRP,\n },\n {\n storage: {\n getLoginResponse: this.#getLoginResponseFromState.bind(this),\n setLoginResponse: this.#setLoginResponseToState.bind(this),\n },\n signing: {\n getIdentifier: this.#snapGetPublicKey.bind(this),\n signMessage: this.#snapSignMessage.bind(this),\n },\n metametrics: this.#metametrics,\n },\n );\n\n this.#keyringController.setupLockedStateSubscriptions();\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n async #getLoginResponseFromState(\n entropySourceId?: string,\n ): Promise<LoginResponse | null> {\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n if (!this.state.srpSessionData?.[resolvedId]) {\n return null;\n }\n return this.state.srpSessionData[resolvedId];\n }\n\n async #setLoginResponseToState(\n loginResponse: LoginResponse,\n entropySourceId?: string,\n ) {\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n const metaMetricsId = await this.#metametrics.getMetaMetricsId();\n this.update((state) => {\n state.isSignedIn = true;\n if (!state.srpSessionData) {\n state.srpSessionData = {};\n }\n state.srpSessionData[resolvedId] = {\n ...loginResponse,\n profile: {\n ...loginResponse.profile,\n metaMetricsId,\n },\n };\n });\n }\n\n #assertIsUnlocked(methodName: string): void {\n if (!this.#isUnlocked) {\n throw new Error(`${methodName} - unable to proceed, wallet is locked`);\n }\n }\n\n async #getPrimaryEntropySourceId(): Promise<string> {\n if (this.#cachedPrimaryEntropySourceId) {\n return this.#cachedPrimaryEntropySourceId;\n }\n const allPublicKeys = await this.#snapGetAllPublicKeys();\n\n if (allPublicKeys.length === 0) {\n throw new Error(\n '#getPrimaryEntropySourceId - No entropy sources found from snap',\n );\n }\n\n const primaryId = allPublicKeys[0][0];\n if (!primaryId) {\n throw new Error(\n '#getPrimaryEntropySourceId - Primary entropy source ID is undefined',\n );\n }\n\n this.#cachedPrimaryEntropySourceId = primaryId;\n return this.#cachedPrimaryEntropySourceId;\n }\n\n public async performSignIn(): Promise<string[]> {\n this.#assertIsUnlocked('performSignIn');\n\n const allPublicKeys = await this.#snapGetAllPublicKeys();\n const accessTokens: string[] = [];\n\n // We iterate sequentially in order to be sure that the first entry\n // is the primary SRP LoginResponse.\n for (const [entropySourceId] of allPublicKeys) {\n const accessToken = await this.#auth.getAccessToken(entropySourceId);\n accessTokens.push(accessToken);\n }\n\n // Pair SRP profiles (idempotent — no-op if already paired)\n if (accessTokens.length >= 2) {\n const previousCanonical = this.#getCanonicalProfileId();\n\n try {\n const profileAliases = await this.#pairSrpProfiles(accessTokens);\n\n const newCanonical = this.#getCanonicalProfileId();\n const profileIdChanged = previousCanonical !== newCanonical;\n const shouldEmitProfileSignInEvent =\n profileIdChanged || profileAliases.length > 0;\n\n if (shouldEmitProfileSignInEvent) {\n this.messenger.publish('AuthenticationController:profileSignIn', {\n profileId: newCanonical ?? '',\n profileAliases,\n profileIdChanged,\n });\n }\n } catch {\n // Pairing failure is non-fatal — retry on next performSignIn\n }\n }\n\n return accessTokens;\n }\n\n async #pairSrpProfiles(accessTokens: string[]): Promise<ProfileAlias[]> {\n if (accessTokens.length < 2) {\n return [];\n }\n const {\n profileAliases,\n profile: { canonicalProfileId },\n } = await this.#auth.pairSrpProfiles(accessTokens, accessTokens[0]);\n this.#propagateCanonical(canonicalProfileId);\n return profileAliases;\n }\n\n #propagateCanonical(canonicalProfileId: string): void {\n const { srpSessionData } = this.state;\n if (!srpSessionData) {\n return;\n }\n\n this.update((state) => {\n for (const key of Object.keys(state.srpSessionData ?? {})) {\n const entry = state.srpSessionData?.[key];\n if (entry?.profile) {\n entry.profile.canonicalProfileId = canonicalProfileId;\n }\n }\n });\n }\n\n #getCanonicalProfileId(): string | null {\n const { srpSessionData } = this.state;\n if (!srpSessionData) {\n return null;\n }\n const firstKey = Object.keys(srpSessionData)[0];\n return firstKey\n ? (srpSessionData[firstKey]?.profile?.canonicalProfileId ?? null)\n : null;\n }\n\n public performSignOut(): void {\n this.#cachedPrimaryEntropySourceId = undefined;\n this.update((state) => {\n state.isSignedIn = false;\n state.srpSessionData = undefined;\n });\n }\n\n /**\n * Returns a bearer token for the specified SRP, logging in if needed.\n *\n * When called without `entropySourceId`, returns the primary (first) SRP's\n * access token, which is effectively the canonical\n * profile's token that can be used by alias-aware consumers for cross-SRP\n * operations.\n *\n * @param entropySourceId - The entropy source ID. Omit for the primary SRP.\n * @returns The OIDC access token.\n */\n public async getBearerToken(entropySourceId?: string): Promise<string> {\n this.#assertIsUnlocked('getBearerToken');\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n return await this.#auth.getAccessToken(resolvedId);\n }\n\n /**\n * Will return a session profile.\n * Logs a user in if a user is not logged in.\n *\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n * @returns profile for the session.\n */\n public async getSessionProfile(\n entropySourceId?: string,\n ): Promise<UserProfile> {\n this.#assertIsUnlocked('getSessionProfile');\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n return await this.#auth.getUserProfile(resolvedId);\n }\n\n public async getUserProfileLineage(\n entropySourceId?: string,\n ): Promise<UserProfileLineage> {\n this.#assertIsUnlocked('getUserProfileLineage');\n const resolvedId =\n entropySourceId ?? (await this.#getPrimaryEntropySourceId());\n return await this.#auth.getUserProfileLineage(resolvedId);\n }\n\n public isSignedIn(): boolean {\n return this.state.isSignedIn;\n }\n\n /**\n * Returns the auth snap public key.\n *\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n * @returns The snap public key.\n */\n async #snapGetPublicKey(entropySourceId?: string): Promise<string> {\n this.#assertIsUnlocked('#snapGetPublicKey');\n\n const result = (await this.messenger.call(\n 'SnapController:handleRequest',\n createSnapPublicKeyRequest(entropySourceId),\n )) as string;\n\n return result;\n }\n\n /**\n * Returns a mapping of entropy source IDs to auth snap public keys.\n *\n * @returns A mapping of entropy source IDs to public keys.\n */\n async #snapGetAllPublicKeys(): Promise<[string, string][]> {\n this.#assertIsUnlocked('#snapGetAllPublicKeys');\n\n const result = (await this.messenger.call(\n 'SnapController:handleRequest',\n createSnapAllPublicKeysRequest(),\n )) as [string, string][];\n\n return result;\n }\n\n #_snapSignMessageCache: Record<`metamask:${string}`, string> = {};\n\n /**\n * Signs a specific message using an underlying auth snap.\n *\n * @param message - A specific tagged message to sign.\n * @param entropySourceId - The entropy source ID used to derive the key,\n * when multiple sources are available (Multi-SRP).\n * @returns A Signature created by the snap.\n */\n async #snapSignMessage(\n message: string,\n entropySourceId?: string,\n ): Promise<string> {\n assertMessageStartsWithMetamask(message);\n\n if (this.#_snapSignMessageCache[message]) {\n return this.#_snapSignMessageCache[message];\n }\n\n this.#assertIsUnlocked('#snapSignMessage');\n\n const result = (await this.messenger.call(\n 'SnapController:handleRequest',\n createSnapSignMessageRequest(message, entropySourceId),\n )) as string;\n\n this.#_snapSignMessageCache[message] = result;\n\n return result;\n }\n}\n"]}
@@ -21,9 +21,18 @@ export declare const MOCK_LOGIN_RESPONSE: {
21
21
  profile_id: string;
22
22
  metametrics_id: string;
23
23
  identifier_id: string;
24
+ /**
25
+ * Wraps a plain-text identifier in a minimal JWT so that client-side
26
+ * JWT validation (exp check) passes in E2E tests. The identifier is
27
+ * stored in the `sub` claim and can be extracted via {@link getE2EIdentifierFromJwt}.
28
+ *
29
+ * @param identifier - The plain-text E2E identifier to wrap.
30
+ * @returns A JWT-shaped string containing the identifier.
31
+ */
24
32
  identifier_type: string;
25
33
  encrypted_storage_key: string;
26
34
  };
35
+ profile_aliases: never[];
27
36
  };
28
37
  export declare const getMockAuthLoginResponse: () => {
29
38
  url: string;
@@ -36,10 +45,19 @@ export declare const getMockAuthLoginResponse: () => {
36
45
  profile_id: string;
37
46
  identifier_id: string;
38
47
  metametrics_id: string;
48
+ /**
49
+ * Wraps a plain-text identifier in a minimal JWT so that client-side
50
+ * JWT validation (exp check) passes in E2E tests. The identifier is
51
+ * stored in the `sub` claim and can be extracted via {@link getE2EIdentifierFromJwt}.
52
+ *
53
+ * @param identifier - The plain-text E2E identifier to wrap.
54
+ * @returns A JWT-shaped string containing the identifier.
55
+ */
39
56
  identifier_type: string;
40
57
  encrypted_storage_key: string;
41
58
  };
42
59
  expires_in: number;
60
+ profile_aliases: never[];
43
61
  };
44
62
  };
45
63
  export declare const MOCK_OATH_TOKEN_RESPONSE: {
@@ -1 +1 @@
1
- {"version":3,"file":"mockResponses.d.cts","sourceRoot":"","sources":["../../../../src/controllers/authentication/mocks/mockResponses.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,mBAAmB;;;;CAA0B,CAAC;AAC3D,eAAO,MAAM,UAAU,QAA4B,CAAC;AACpD,eAAO,MAAM,QAAQ,upBAAe,CAAC;AAErC,eAAO,MAAM,wBAAwB;;;mBAK3B,OAAO,SACJ,MAAM,iDACiC,MAAM,KAAK,MAAM;;;;;CAcpE,CAAC;AAEF,eAAO,MAAM,mBAAmB;;;;;;;;;;CAA8B,CAAC;AAE/D,eAAO,MAAM,wBAAwB;;;iCAMJ;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;CAgBvD,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAA+B,CAAC;AAoBrE;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,UAAW,MAAM,KAAG,MAavD,CAAC;AAEF,eAAO,MAAM,8BAA8B;;;iCAIV,MAAM;;;;CAetC,CAAC"}
1
+ {"version":3,"file":"mockResponses.d.cts","sourceRoot":"","sources":["../../../../src/controllers/authentication/mocks/mockResponses.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,mBAAmB;;;;CAA0B,CAAC;AAC3D,eAAO,MAAM,UAAU,QAA4B,CAAC;AACpD,eAAO,MAAM,QAAQ,upBAAe,CAAC;AAErC,eAAO,MAAM,wBAAwB;;;mBAK3B,OAAO,SACJ,MAAM,iDACiC,MAAM,KAAK,MAAM;;;;;CAcpE,CAAC;AAEF,eAAO,MAAM,mBAAmB;;;;;;;QA8BhC;;;;;;;WAOG;;;;;CArC2D,CAAC;AAE/D,eAAO,MAAM,wBAAwB;;;iCAMJ;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE;;;;;;YAsBxD;;;;;;;eAOG;;;;;;;CAbF,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAA+B,CAAC;AAoBrE;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,UAAW,MAAM,KAAG,MAavD,CAAC;AAEF,eAAO,MAAM,8BAA8B;;;iCAIV,MAAM;;;;CAetC,CAAC"}
@@ -21,9 +21,18 @@ export declare const MOCK_LOGIN_RESPONSE: {
21
21
  profile_id: string;
22
22
  metametrics_id: string;
23
23
  identifier_id: string;
24
+ /**
25
+ * Wraps a plain-text identifier in a minimal JWT so that client-side
26
+ * JWT validation (exp check) passes in E2E tests. The identifier is
27
+ * stored in the `sub` claim and can be extracted via {@link getE2EIdentifierFromJwt}.
28
+ *
29
+ * @param identifier - The plain-text E2E identifier to wrap.
30
+ * @returns A JWT-shaped string containing the identifier.
31
+ */
24
32
  identifier_type: string;
25
33
  encrypted_storage_key: string;
26
34
  };
35
+ profile_aliases: never[];
27
36
  };
28
37
  export declare const getMockAuthLoginResponse: () => {
29
38
  url: string;
@@ -36,10 +45,19 @@ export declare const getMockAuthLoginResponse: () => {
36
45
  profile_id: string;
37
46
  identifier_id: string;
38
47
  metametrics_id: string;
48
+ /**
49
+ * Wraps a plain-text identifier in a minimal JWT so that client-side
50
+ * JWT validation (exp check) passes in E2E tests. The identifier is
51
+ * stored in the `sub` claim and can be extracted via {@link getE2EIdentifierFromJwt}.
52
+ *
53
+ * @param identifier - The plain-text E2E identifier to wrap.
54
+ * @returns A JWT-shaped string containing the identifier.
55
+ */
39
56
  identifier_type: string;
40
57
  encrypted_storage_key: string;
41
58
  };
42
59
  expires_in: number;
60
+ profile_aliases: never[];
43
61
  };
44
62
  };
45
63
  export declare const MOCK_OATH_TOKEN_RESPONSE: {
@@ -1 +1 @@
1
- {"version":3,"file":"mockResponses.d.mts","sourceRoot":"","sources":["../../../../src/controllers/authentication/mocks/mockResponses.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,mBAAmB;;;;CAA0B,CAAC;AAC3D,eAAO,MAAM,UAAU,QAA4B,CAAC;AACpD,eAAO,MAAM,QAAQ,upBAAe,CAAC;AAErC,eAAO,MAAM,wBAAwB;;;mBAK3B,OAAO,SACJ,MAAM,iDACiC,MAAM,KAAK,MAAM;;;;;CAcpE,CAAC;AAEF,eAAO,MAAM,mBAAmB;;;;;;;;;;CAA8B,CAAC;AAE/D,eAAO,MAAM,wBAAwB;;;iCAMJ;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE;;;;;;;;;;;CAgBvD,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAA+B,CAAC;AAoBrE;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,UAAW,MAAM,KAAG,MAavD,CAAC;AAEF,eAAO,MAAM,8BAA8B;;;iCAIV,MAAM;;;;CAetC,CAAC"}
1
+ {"version":3,"file":"mockResponses.d.mts","sourceRoot":"","sources":["../../../../src/controllers/authentication/mocks/mockResponses.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,mBAAmB;;;;CAA0B,CAAC;AAC3D,eAAO,MAAM,UAAU,QAA4B,CAAC;AACpD,eAAO,MAAM,QAAQ,upBAAe,CAAC;AAErC,eAAO,MAAM,wBAAwB;;;mBAK3B,OAAO,SACJ,MAAM,iDACiC,MAAM,KAAK,MAAM;;;;;CAcpE,CAAC;AAEF,eAAO,MAAM,mBAAmB;;;;;;;QA8BhC;;;;;;;WAOG;;;;;CArC2D,CAAC;AAE/D,eAAO,MAAM,wBAAwB;;;iCAMJ;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE;;;;;;YAsBxD;;;;;;;eAOG;;;;;;;CAbF,CAAC;AAEF,eAAO,MAAM,wBAAwB;;;CAA+B,CAAC;AAoBrE;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,UAAW,MAAM,KAAG,MAavD,CAAC;AAEF,eAAO,MAAM,8BAA8B;;;iCAIV,MAAM;;;;CAetC,CAAC"}
@@ -41,6 +41,7 @@ const eip_6963_metamask_provider_1 = require("../utils/eip-6963-metamask-provide
41
41
  const messaging_signing_snap_requests_1 = require("../utils/messaging-signing-snap-requests.cjs");
42
42
  const validate_login_response_1 = require("../utils/validate-login-response.cjs");
43
43
  const services_1 = require("./services.cjs");
44
+ const identifier_1 = require("./utils/identifier.cjs");
44
45
  const timeUtils = __importStar(require("./utils/time.cjs"));
45
46
  const getDefaultEIP6963Provider = async () => {
46
47
  const provider = await (0, eip_6963_metamask_provider_1.getMetaMaskProviderEIP6963)();
@@ -113,6 +114,9 @@ class SRPJwtBearerAuth {
113
114
  const accessToken = await this.getAccessToken(entropySourceId);
114
115
  return await (0, services_1.getUserProfileLineage)(__classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env, accessToken);
115
116
  }
117
+ async pairSrpProfiles(accessTokens, authAccessToken) {
118
+ return await (0, services_1.pairProfiles)(accessTokens, authAccessToken, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env);
119
+ }
116
120
  async signMessage(message, entropySourceId) {
117
121
  return await __classPrivateFieldGet(this, _SRPJwtBearerAuth_options, "f").signing.signMessage(message, entropySourceId);
118
122
  }
@@ -156,11 +160,24 @@ async function _SRPJwtBearerAuth_getAuthSession(entropySourceId) {
156
160
  const signature = await this.signMessage(rawMessage, entropySourceId);
157
161
  // Authenticate
158
162
  const authResponse = await (0, services_1.authenticate)(rawMessage, signature, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").type, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env, __classPrivateFieldGet(this, _SRPJwtBearerAuth_metametrics, "f"));
163
+ // Resolve original profileId from aliases.
164
+ // This is done mainly to preserve the original profileId for storage key derivation
165
+ // until we migrate to the canonical profileId storage system.
166
+ const canonicalProfileId = authResponse.profile.profileId;
167
+ const profile = { ...authResponse.profile };
168
+ if (authResponse.profileAliases?.length > 0) {
169
+ const targetIdentifierId = (0, identifier_1.computeIdentifierId)(publicKey, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env);
170
+ const targetAlias = authResponse.profileAliases.find((alias) => alias.identifierIds.some((id) => id.id === targetIdentifierId));
171
+ if (targetAlias) {
172
+ profile.profileId = targetAlias.aliasProfileId;
173
+ }
174
+ }
175
+ profile.canonicalProfileId = canonicalProfileId;
159
176
  // Authorize
160
177
  const tokenResponse = await (0, services_1.authorizeOIDC)(authResponse.token, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").platform);
161
178
  // Save
162
179
  const result = {
163
- profile: authResponse.profile,
180
+ profile,
164
181
  token: tokenResponse,
165
182
  };
166
183
  await __classPrivateFieldGet(this, _SRPJwtBearerAuth_options, "f").storage.setLoginResponse(result, entropySourceId);
@@ -1 +1 @@
1
- {"version":3,"file":"flow-srp.cjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Eip1193Provider } from 'ethers';\n\nimport type { MetaMetricsAuth } from '../../shared/types/services';\nimport { ValidationError, RateLimitedError } from '../errors';\nimport { getMetaMaskProviderEIP6963 } from '../utils/eip-6963-metamask-provider';\nimport {\n MESSAGE_SIGNING_SNAP,\n assertMessageStartsWithMetamask,\n connectSnap,\n isSnapConnected,\n} from '../utils/messaging-signing-snap-requests';\nimport { validateLoginResponse } from '../utils/validate-login-response';\nimport {\n authenticate,\n authorizeOIDC,\n getNonce,\n getUserProfileLineage,\n} from './services';\nimport type {\n AuthConfig,\n AuthSigningOptions,\n AuthStorageOptions,\n AuthType,\n IBaseAuth,\n LoginResponse,\n UserProfile,\n UserProfileLineage,\n} from './types';\nimport * as timeUtils from './utils/time';\n\ntype JwtBearerAuth_SRP_Options = {\n storage: AuthStorageOptions;\n signing?: AuthSigningOptions;\n rateLimitRetry?: {\n cooldownDefaultMs?: number; // default cooldown when 429 has no Retry-After\n maxLoginRetries?: number; // maximum number of login retries on rate limit\n };\n};\n\nconst getDefaultEIP6963Provider = async () => {\n const provider = await getMetaMaskProviderEIP6963();\n if (!provider) {\n throw new ValidationError('No MetaMask wallet connected');\n }\n return provider;\n};\n\nconst getDefaultEIP6963SigningOptions = (\n customProvider?: Eip1193Provider,\n): AuthSigningOptions => ({\n getIdentifier: async (entropySourceId?: string): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n return await MESSAGE_SIGNING_SNAP.getPublicKey(provider, entropySourceId);\n },\n signMessage: async (\n message: string,\n entropySourceId?: string,\n ): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n assertMessageStartsWithMetamask(message);\n return await MESSAGE_SIGNING_SNAP.signMessage(\n provider,\n message,\n entropySourceId,\n );\n },\n});\n\nexport class SRPJwtBearerAuth implements IBaseAuth {\n readonly #config: AuthConfig;\n\n readonly #options: {\n storage: AuthStorageOptions;\n signing: AuthSigningOptions;\n };\n\n readonly #metametrics?: MetaMetricsAuth;\n\n // Map to store ongoing login promises by entropySourceId\n readonly #ongoingLogins = new Map<\n string | undefined,\n Promise<LoginResponse>\n >();\n\n // Default cooldown when 429 has no Retry-After header\n readonly #cooldownDefaultMs: number;\n\n // Maximum number of login retries on rate limit errors\n readonly #maxLoginRetries: number;\n\n #customProvider?: Eip1193Provider;\n\n constructor(\n config: AuthConfig & { type: AuthType.SRP },\n options: JwtBearerAuth_SRP_Options & {\n customProvider?: Eip1193Provider;\n metametrics?: MetaMetricsAuth;\n },\n ) {\n this.#config = config;\n this.#customProvider = options.customProvider;\n this.#options = {\n storage: options.storage,\n signing:\n options.signing ??\n getDefaultEIP6963SigningOptions(this.#customProvider),\n };\n this.#metametrics = options.metametrics;\n\n // Apply rate limit retry config if provided\n this.#cooldownDefaultMs =\n options.rateLimitRetry?.cooldownDefaultMs ?? 10000;\n this.#maxLoginRetries = options.rateLimitRetry?.maxLoginRetries ?? 1;\n }\n\n setCustomProvider(provider: Eip1193Provider) {\n this.#customProvider = provider;\n this.#options.signing = getDefaultEIP6963SigningOptions(provider);\n }\n\n // TODO: might be easier to keep entropySourceId as a class param and use multiple SRPJwtBearerAuth instances where needed\n async getAccessToken(entropySourceId?: string): Promise<string> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.token.accessToken;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.token.accessToken;\n }\n\n async getUserProfile(entropySourceId?: string): Promise<UserProfile> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.profile;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.profile;\n }\n\n async getIdentifier(entropySourceId?: string): Promise<string> {\n return await this.#options.signing.getIdentifier(entropySourceId);\n }\n\n async getUserProfileLineage(\n entropySourceId?: string,\n ): Promise<UserProfileLineage> {\n const accessToken = await this.getAccessToken(entropySourceId);\n return await getUserProfileLineage(this.#config.env, accessToken);\n }\n\n async signMessage(\n message: string,\n entropySourceId?: string,\n ): Promise<string> {\n return await this.#options.signing.signMessage(message, entropySourceId);\n }\n\n async isSnapConnected(): Promise<boolean> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n if (!provider) {\n return false;\n }\n\n const isConnected = await isSnapConnected(provider);\n return isConnected;\n }\n\n async connectSnap(): Promise<string> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n\n const res = await connectSnap(provider);\n return res;\n }\n\n // convert expiresIn from seconds to milliseconds and use 90% of expiresIn\n async #getAuthSession(\n entropySourceId?: string,\n ): Promise<LoginResponse | null> {\n const auth = await this.#options.storage.getLoginResponse(entropySourceId);\n if (!validateLoginResponse(auth)) {\n return null;\n }\n\n const currentTime = Date.now();\n const sessionAge = currentTime - auth.token.obtainedAt;\n const refreshThreshold = auth.token.expiresIn * 1000 * 0.9;\n\n if (sessionAge < refreshThreshold) {\n return auth;\n }\n return null;\n }\n\n async #login(entropySourceId?: string): Promise<LoginResponse> {\n // Use a deferred login to avoid race conditions\n return await this.#deferredLogin(entropySourceId);\n }\n\n async #performLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Nonce\n const publicKey = await this.getIdentifier(entropySourceId);\n const nonceRes = await getNonce(publicKey, this.#config.env);\n\n const rawMessage = this.#createSrpLoginRawMessage(\n nonceRes.nonce,\n publicKey,\n );\n const signature = await this.signMessage(rawMessage, entropySourceId);\n\n // Authenticate\n const authResponse = await authenticate(\n rawMessage,\n signature,\n this.#config.type,\n this.#config.env,\n this.#metametrics,\n );\n\n // Authorize\n const tokenResponse = await authorizeOIDC(\n authResponse.token,\n this.#config.env,\n this.#config.platform,\n );\n\n // Save\n const result: LoginResponse = {\n profile: authResponse.profile,\n token: tokenResponse,\n };\n\n await this.#options.storage.setLoginResponse(result, entropySourceId);\n\n return result;\n }\n\n async #deferredLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Check if there's already an ongoing login for this entropySourceId\n const existingLogin = this.#ongoingLogins.get(entropySourceId);\n if (existingLogin) {\n return existingLogin;\n }\n\n // Create a new login promise\n const loginPromise = this.#loginWithRetry(entropySourceId);\n\n // Store the promise in the map\n this.#ongoingLogins.set(entropySourceId, loginPromise);\n\n try {\n // Wait for the login to complete\n return await loginPromise;\n } finally {\n // Always clean up the ongoing login promise when done\n this.#ongoingLogins.delete(entropySourceId);\n }\n }\n\n async #loginWithRetry(entropySourceId?: string): Promise<LoginResponse> {\n // Allow max attempts: initial + maxLoginRetries on 429\n for (let attempt = 0; attempt < 1 + this.#maxLoginRetries; attempt += 1) {\n try {\n return await this.#performLogin(entropySourceId);\n } catch (e) {\n // Only retry on rate-limit (429) errors\n if (!RateLimitedError.isRateLimitError(e)) {\n throw e;\n }\n\n // If we've exhausted attempts, rethrow\n if (attempt >= this.#maxLoginRetries) {\n throw e;\n }\n\n // Wait for Retry-After or default cooldown\n const waitMs = e.retryAfterMs ?? this.#cooldownDefaultMs;\n await timeUtils.delay(waitMs);\n\n // Loop continues to retry\n }\n }\n\n // Should never reach here due to loop logic, but TypeScript needs a return\n throw new Error('Unexpected: login loop exhausted without result');\n }\n\n #createSrpLoginRawMessage(\n nonce: string,\n publicKey: string,\n ): `metamask:${string}:${string}` {\n return `metamask:${nonce}:${publicKey}` as const;\n }\n}\n"]}
1
+ {"version":3,"file":"flow-srp.cjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Eip1193Provider } from 'ethers';\n\nimport type { MetaMetricsAuth } from '../../shared/types/services';\nimport { ValidationError, RateLimitedError } from '../errors';\nimport { getMetaMaskProviderEIP6963 } from '../utils/eip-6963-metamask-provider';\nimport {\n MESSAGE_SIGNING_SNAP,\n assertMessageStartsWithMetamask,\n connectSnap,\n isSnapConnected,\n} from '../utils/messaging-signing-snap-requests';\nimport { validateLoginResponse } from '../utils/validate-login-response';\nimport {\n authenticate,\n authorizeOIDC,\n getNonce,\n getUserProfileLineage,\n pairProfiles,\n} from './services';\nimport type { PairProfilesResponse } from './services';\nimport type {\n AuthConfig,\n AuthSigningOptions,\n AuthStorageOptions,\n AuthType,\n IBaseAuth,\n LoginResponse,\n UserProfile,\n UserProfileLineage,\n} from './types';\nimport { computeIdentifierId } from './utils/identifier';\nimport * as timeUtils from './utils/time';\n\ntype JwtBearerAuth_SRP_Options = {\n storage: AuthStorageOptions;\n signing?: AuthSigningOptions;\n rateLimitRetry?: {\n cooldownDefaultMs?: number; // default cooldown when 429 has no Retry-After\n maxLoginRetries?: number; // maximum number of login retries on rate limit\n };\n};\n\nconst getDefaultEIP6963Provider = async () => {\n const provider = await getMetaMaskProviderEIP6963();\n if (!provider) {\n throw new ValidationError('No MetaMask wallet connected');\n }\n return provider;\n};\n\nconst getDefaultEIP6963SigningOptions = (\n customProvider?: Eip1193Provider,\n): AuthSigningOptions => ({\n getIdentifier: async (entropySourceId?: string): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n return await MESSAGE_SIGNING_SNAP.getPublicKey(provider, entropySourceId);\n },\n signMessage: async (\n message: string,\n entropySourceId?: string,\n ): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n assertMessageStartsWithMetamask(message);\n return await MESSAGE_SIGNING_SNAP.signMessage(\n provider,\n message,\n entropySourceId,\n );\n },\n});\n\nexport class SRPJwtBearerAuth implements IBaseAuth {\n readonly #config: AuthConfig;\n\n readonly #options: {\n storage: AuthStorageOptions;\n signing: AuthSigningOptions;\n };\n\n readonly #metametrics?: MetaMetricsAuth;\n\n // Map to store ongoing login promises by entropySourceId\n readonly #ongoingLogins = new Map<\n string | undefined,\n Promise<LoginResponse>\n >();\n\n // Default cooldown when 429 has no Retry-After header\n readonly #cooldownDefaultMs: number;\n\n // Maximum number of login retries on rate limit errors\n readonly #maxLoginRetries: number;\n\n #customProvider?: Eip1193Provider;\n\n constructor(\n config: AuthConfig & { type: AuthType.SRP },\n options: JwtBearerAuth_SRP_Options & {\n customProvider?: Eip1193Provider;\n metametrics?: MetaMetricsAuth;\n },\n ) {\n this.#config = config;\n this.#customProvider = options.customProvider;\n this.#options = {\n storage: options.storage,\n signing:\n options.signing ??\n getDefaultEIP6963SigningOptions(this.#customProvider),\n };\n this.#metametrics = options.metametrics;\n\n // Apply rate limit retry config if provided\n this.#cooldownDefaultMs =\n options.rateLimitRetry?.cooldownDefaultMs ?? 10000;\n this.#maxLoginRetries = options.rateLimitRetry?.maxLoginRetries ?? 1;\n }\n\n setCustomProvider(provider: Eip1193Provider) {\n this.#customProvider = provider;\n this.#options.signing = getDefaultEIP6963SigningOptions(provider);\n }\n\n // TODO: might be easier to keep entropySourceId as a class param and use multiple SRPJwtBearerAuth instances where needed\n async getAccessToken(entropySourceId?: string): Promise<string> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.token.accessToken;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.token.accessToken;\n }\n\n async getUserProfile(entropySourceId?: string): Promise<UserProfile> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.profile;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.profile;\n }\n\n async getIdentifier(entropySourceId?: string): Promise<string> {\n return await this.#options.signing.getIdentifier(entropySourceId);\n }\n\n async getUserProfileLineage(\n entropySourceId?: string,\n ): Promise<UserProfileLineage> {\n const accessToken = await this.getAccessToken(entropySourceId);\n return await getUserProfileLineage(this.#config.env, accessToken);\n }\n\n async pairSrpProfiles(\n accessTokens: string[],\n authAccessToken: string,\n ): Promise<PairProfilesResponse> {\n return await pairProfiles(accessTokens, authAccessToken, this.#config.env);\n }\n\n async signMessage(\n message: string,\n entropySourceId?: string,\n ): Promise<string> {\n return await this.#options.signing.signMessage(message, entropySourceId);\n }\n\n async isSnapConnected(): Promise<boolean> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n if (!provider) {\n return false;\n }\n\n const isConnected = await isSnapConnected(provider);\n return isConnected;\n }\n\n async connectSnap(): Promise<string> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n\n const res = await connectSnap(provider);\n return res;\n }\n\n // convert expiresIn from seconds to milliseconds and use 90% of expiresIn\n async #getAuthSession(\n entropySourceId?: string,\n ): Promise<LoginResponse | null> {\n const auth = await this.#options.storage.getLoginResponse(entropySourceId);\n if (!validateLoginResponse(auth)) {\n return null;\n }\n\n const currentTime = Date.now();\n const sessionAge = currentTime - auth.token.obtainedAt;\n const refreshThreshold = auth.token.expiresIn * 1000 * 0.9;\n\n if (sessionAge < refreshThreshold) {\n return auth;\n }\n return null;\n }\n\n async #login(entropySourceId?: string): Promise<LoginResponse> {\n // Use a deferred login to avoid race conditions\n return await this.#deferredLogin(entropySourceId);\n }\n\n async #performLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Nonce\n const publicKey = await this.getIdentifier(entropySourceId);\n const nonceRes = await getNonce(publicKey, this.#config.env);\n\n const rawMessage = this.#createSrpLoginRawMessage(\n nonceRes.nonce,\n publicKey,\n );\n const signature = await this.signMessage(rawMessage, entropySourceId);\n\n // Authenticate\n const authResponse = await authenticate(\n rawMessage,\n signature,\n this.#config.type,\n this.#config.env,\n this.#metametrics,\n );\n\n // Resolve original profileId from aliases.\n // This is done mainly to preserve the original profileId for storage key derivation\n // until we migrate to the canonical profileId storage system.\n const canonicalProfileId = authResponse.profile.profileId;\n const profile = { ...authResponse.profile };\n\n if (authResponse.profileAliases?.length > 0) {\n const targetIdentifierId = computeIdentifierId(\n publicKey,\n this.#config.env,\n );\n\n const targetAlias = authResponse.profileAliases.find((alias) =>\n alias.identifierIds.some((id) => id.id === targetIdentifierId),\n );\n\n if (targetAlias) {\n profile.profileId = targetAlias.aliasProfileId;\n }\n }\n\n profile.canonicalProfileId = canonicalProfileId;\n\n // Authorize\n const tokenResponse = await authorizeOIDC(\n authResponse.token,\n this.#config.env,\n this.#config.platform,\n );\n\n // Save\n const result: LoginResponse = {\n profile,\n token: tokenResponse,\n };\n\n await this.#options.storage.setLoginResponse(result, entropySourceId);\n\n return result;\n }\n\n async #deferredLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Check if there's already an ongoing login for this entropySourceId\n const existingLogin = this.#ongoingLogins.get(entropySourceId);\n if (existingLogin) {\n return existingLogin;\n }\n\n // Create a new login promise\n const loginPromise = this.#loginWithRetry(entropySourceId);\n\n // Store the promise in the map\n this.#ongoingLogins.set(entropySourceId, loginPromise);\n\n try {\n // Wait for the login to complete\n return await loginPromise;\n } finally {\n // Always clean up the ongoing login promise when done\n this.#ongoingLogins.delete(entropySourceId);\n }\n }\n\n async #loginWithRetry(entropySourceId?: string): Promise<LoginResponse> {\n // Allow max attempts: initial + maxLoginRetries on 429\n for (let attempt = 0; attempt < 1 + this.#maxLoginRetries; attempt += 1) {\n try {\n return await this.#performLogin(entropySourceId);\n } catch (e) {\n // Only retry on rate-limit (429) errors\n if (!RateLimitedError.isRateLimitError(e)) {\n throw e;\n }\n\n // If we've exhausted attempts, rethrow\n if (attempt >= this.#maxLoginRetries) {\n throw e;\n }\n\n // Wait for Retry-After or default cooldown\n const waitMs = e.retryAfterMs ?? this.#cooldownDefaultMs;\n await timeUtils.delay(waitMs);\n\n // Loop continues to retry\n }\n }\n\n // Should never reach here due to loop logic, but TypeScript needs a return\n throw new Error('Unexpected: login loop exhausted without result');\n }\n\n #createSrpLoginRawMessage(\n nonce: string,\n publicKey: string,\n ): `metamask:${string}:${string}` {\n return `metamask:${nonce}:${publicKey}` as const;\n }\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { Eip1193Provider } from "ethers";
2
2
  import type { MetaMetricsAuth } from "../../shared/types/services.cjs";
3
+ import type { PairProfilesResponse } from "./services.cjs";
3
4
  import type { AuthConfig, AuthSigningOptions, AuthStorageOptions, AuthType, IBaseAuth, UserProfile, UserProfileLineage } from "./types.cjs";
4
5
  type JwtBearerAuth_SRP_Options = {
5
6
  storage: AuthStorageOptions;
@@ -22,6 +23,7 @@ export declare class SRPJwtBearerAuth implements IBaseAuth {
22
23
  getUserProfile(entropySourceId?: string): Promise<UserProfile>;
23
24
  getIdentifier(entropySourceId?: string): Promise<string>;
24
25
  getUserProfileLineage(entropySourceId?: string): Promise<UserProfileLineage>;
26
+ pairSrpProfiles(accessTokens: string[], authAccessToken: string): Promise<PairProfilesResponse>;
25
27
  signMessage(message: string, entropySourceId?: string): Promise<string>;
26
28
  isSnapConnected(): Promise<boolean>;
27
29
  connectSnap(): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"flow-srp.d.cts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,wCAAoC;AAgBnE,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,QAAQ,EACR,SAAS,EAET,WAAW,EACX,kBAAkB,EACnB,oBAAgB;AAGjB,KAAK,yBAAyB,GAAG;IAC/B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,cAAc,CAAC,EAAE;QACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH,CAAC;AA+BF,qBAAa,gBAAiB,YAAW,SAAS;;gBAyB9C,MAAM,EAAE,UAAU,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAA;KAAE,EAC3C,OAAO,EAAE,yBAAyB,GAAG;QACnC,cAAc,CAAC,EAAE,eAAe,CAAC;QACjC,WAAW,CAAC,EAAE,eAAe,CAAC;KAC/B;IAkBH,iBAAiB,CAAC,QAAQ,EAAE,eAAe;IAMrC,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzD,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAU9D,aAAa,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIxD,qBAAqB,CACzB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,kBAAkB,CAAC;IAKxB,WAAW,CACf,OAAO,EAAE,MAAM,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;IAIZ,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAWnC,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;CA8HrC"}
1
+ {"version":3,"file":"flow-srp.d.cts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,wCAAoC;AAiBnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAmB;AACvD,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,QAAQ,EACR,SAAS,EAET,WAAW,EACX,kBAAkB,EACnB,oBAAgB;AAIjB,KAAK,yBAAyB,GAAG;IAC/B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,cAAc,CAAC,EAAE;QACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH,CAAC;AA+BF,qBAAa,gBAAiB,YAAW,SAAS;;gBAyB9C,MAAM,EAAE,UAAU,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAA;KAAE,EAC3C,OAAO,EAAE,yBAAyB,GAAG;QACnC,cAAc,CAAC,EAAE,eAAe,CAAC;QACjC,WAAW,CAAC,EAAE,eAAe,CAAC;KAC/B;IAkBH,iBAAiB,CAAC,QAAQ,EAAE,eAAe;IAMrC,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzD,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAU9D,aAAa,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIxD,qBAAqB,CACzB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,kBAAkB,CAAC;IAKxB,eAAe,CACnB,YAAY,EAAE,MAAM,EAAE,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,oBAAoB,CAAC;IAI1B,WAAW,CACf,OAAO,EAAE,MAAM,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;IAIZ,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAWnC,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;CAqJrC"}
@@ -1,5 +1,6 @@
1
1
  import type { Eip1193Provider } from "ethers";
2
2
  import type { MetaMetricsAuth } from "../../shared/types/services.mjs";
3
+ import type { PairProfilesResponse } from "./services.mjs";
3
4
  import type { AuthConfig, AuthSigningOptions, AuthStorageOptions, AuthType, IBaseAuth, UserProfile, UserProfileLineage } from "./types.mjs";
4
5
  type JwtBearerAuth_SRP_Options = {
5
6
  storage: AuthStorageOptions;
@@ -22,6 +23,7 @@ export declare class SRPJwtBearerAuth implements IBaseAuth {
22
23
  getUserProfile(entropySourceId?: string): Promise<UserProfile>;
23
24
  getIdentifier(entropySourceId?: string): Promise<string>;
24
25
  getUserProfileLineage(entropySourceId?: string): Promise<UserProfileLineage>;
26
+ pairSrpProfiles(accessTokens: string[], authAccessToken: string): Promise<PairProfilesResponse>;
25
27
  signMessage(message: string, entropySourceId?: string): Promise<string>;
26
28
  isSnapConnected(): Promise<boolean>;
27
29
  connectSnap(): Promise<string>;
@@ -1 +1 @@
1
- {"version":3,"file":"flow-srp.d.mts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,wCAAoC;AAgBnE,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,QAAQ,EACR,SAAS,EAET,WAAW,EACX,kBAAkB,EACnB,oBAAgB;AAGjB,KAAK,yBAAyB,GAAG;IAC/B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,cAAc,CAAC,EAAE;QACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH,CAAC;AA+BF,qBAAa,gBAAiB,YAAW,SAAS;;gBAyB9C,MAAM,EAAE,UAAU,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAA;KAAE,EAC3C,OAAO,EAAE,yBAAyB,GAAG;QACnC,cAAc,CAAC,EAAE,eAAe,CAAC;QACjC,WAAW,CAAC,EAAE,eAAe,CAAC;KAC/B;IAkBH,iBAAiB,CAAC,QAAQ,EAAE,eAAe;IAMrC,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzD,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAU9D,aAAa,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIxD,qBAAqB,CACzB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,kBAAkB,CAAC;IAKxB,WAAW,CACf,OAAO,EAAE,MAAM,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;IAIZ,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAWnC,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;CA8HrC"}
1
+ {"version":3,"file":"flow-srp.d.mts","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe;AAE9C,OAAO,KAAK,EAAE,eAAe,EAAE,wCAAoC;AAiBnE,OAAO,KAAK,EAAE,oBAAoB,EAAE,uBAAmB;AACvD,OAAO,KAAK,EACV,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,QAAQ,EACR,SAAS,EAET,WAAW,EACX,kBAAkB,EACnB,oBAAgB;AAIjB,KAAK,yBAAyB,GAAG;IAC/B,OAAO,EAAE,kBAAkB,CAAC;IAC5B,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,cAAc,CAAC,EAAE;QACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;QAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH,CAAC;AA+BF,qBAAa,gBAAiB,YAAW,SAAS;;gBAyB9C,MAAM,EAAE,UAAU,GAAG;QAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAA;KAAE,EAC3C,OAAO,EAAE,yBAAyB,GAAG;QACnC,cAAc,CAAC,EAAE,eAAe,CAAC;QACjC,WAAW,CAAC,EAAE,eAAe,CAAC;KAC/B;IAkBH,iBAAiB,CAAC,QAAQ,EAAE,eAAe;IAMrC,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzD,cAAc,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAU9D,aAAa,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIxD,qBAAqB,CACzB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,kBAAkB,CAAC;IAKxB,eAAe,CACnB,YAAY,EAAE,MAAM,EAAE,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC,oBAAoB,CAAC;IAI1B,WAAW,CACf,OAAO,EAAE,MAAM,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,MAAM,CAAC;IAIZ,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAWnC,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;CAqJrC"}
@@ -14,7 +14,8 @@ import { ValidationError, RateLimitedError } from "../errors.mjs";
14
14
  import { getMetaMaskProviderEIP6963 } from "../utils/eip-6963-metamask-provider.mjs";
15
15
  import { MESSAGE_SIGNING_SNAP, assertMessageStartsWithMetamask, connectSnap, isSnapConnected } from "../utils/messaging-signing-snap-requests.mjs";
16
16
  import { validateLoginResponse } from "../utils/validate-login-response.mjs";
17
- import { authenticate, authorizeOIDC, getNonce, getUserProfileLineage } from "./services.mjs";
17
+ import { authenticate, authorizeOIDC, getNonce, getUserProfileLineage, pairProfiles } from "./services.mjs";
18
+ import { computeIdentifierId } from "./utils/identifier.mjs";
18
19
  import * as timeUtils from "./utils/time.mjs";
19
20
  const getDefaultEIP6963Provider = async () => {
20
21
  const provider = await getMetaMaskProviderEIP6963();
@@ -87,6 +88,9 @@ export class SRPJwtBearerAuth {
87
88
  const accessToken = await this.getAccessToken(entropySourceId);
88
89
  return await getUserProfileLineage(__classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env, accessToken);
89
90
  }
91
+ async pairSrpProfiles(accessTokens, authAccessToken) {
92
+ return await pairProfiles(accessTokens, authAccessToken, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env);
93
+ }
90
94
  async signMessage(message, entropySourceId) {
91
95
  return await __classPrivateFieldGet(this, _SRPJwtBearerAuth_options, "f").signing.signMessage(message, entropySourceId);
92
96
  }
@@ -129,11 +133,24 @@ async function _SRPJwtBearerAuth_getAuthSession(entropySourceId) {
129
133
  const signature = await this.signMessage(rawMessage, entropySourceId);
130
134
  // Authenticate
131
135
  const authResponse = await authenticate(rawMessage, signature, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").type, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env, __classPrivateFieldGet(this, _SRPJwtBearerAuth_metametrics, "f"));
136
+ // Resolve original profileId from aliases.
137
+ // This is done mainly to preserve the original profileId for storage key derivation
138
+ // until we migrate to the canonical profileId storage system.
139
+ const canonicalProfileId = authResponse.profile.profileId;
140
+ const profile = { ...authResponse.profile };
141
+ if (authResponse.profileAliases?.length > 0) {
142
+ const targetIdentifierId = computeIdentifierId(publicKey, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env);
143
+ const targetAlias = authResponse.profileAliases.find((alias) => alias.identifierIds.some((id) => id.id === targetIdentifierId));
144
+ if (targetAlias) {
145
+ profile.profileId = targetAlias.aliasProfileId;
146
+ }
147
+ }
148
+ profile.canonicalProfileId = canonicalProfileId;
132
149
  // Authorize
133
150
  const tokenResponse = await authorizeOIDC(authResponse.token, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").env, __classPrivateFieldGet(this, _SRPJwtBearerAuth_config, "f").platform);
134
151
  // Save
135
152
  const result = {
136
- profile: authResponse.profile,
153
+ profile,
137
154
  token: tokenResponse,
138
155
  };
139
156
  await __classPrivateFieldGet(this, _SRPJwtBearerAuth_options, "f").storage.setLoginResponse(result, entropySourceId);
@@ -1 +1 @@
1
- {"version":3,"file":"flow-srp.mjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Eip1193Provider } from 'ethers';\n\nimport type { MetaMetricsAuth } from '../../shared/types/services';\nimport { ValidationError, RateLimitedError } from '../errors';\nimport { getMetaMaskProviderEIP6963 } from '../utils/eip-6963-metamask-provider';\nimport {\n MESSAGE_SIGNING_SNAP,\n assertMessageStartsWithMetamask,\n connectSnap,\n isSnapConnected,\n} from '../utils/messaging-signing-snap-requests';\nimport { validateLoginResponse } from '../utils/validate-login-response';\nimport {\n authenticate,\n authorizeOIDC,\n getNonce,\n getUserProfileLineage,\n} from './services';\nimport type {\n AuthConfig,\n AuthSigningOptions,\n AuthStorageOptions,\n AuthType,\n IBaseAuth,\n LoginResponse,\n UserProfile,\n UserProfileLineage,\n} from './types';\nimport * as timeUtils from './utils/time';\n\ntype JwtBearerAuth_SRP_Options = {\n storage: AuthStorageOptions;\n signing?: AuthSigningOptions;\n rateLimitRetry?: {\n cooldownDefaultMs?: number; // default cooldown when 429 has no Retry-After\n maxLoginRetries?: number; // maximum number of login retries on rate limit\n };\n};\n\nconst getDefaultEIP6963Provider = async () => {\n const provider = await getMetaMaskProviderEIP6963();\n if (!provider) {\n throw new ValidationError('No MetaMask wallet connected');\n }\n return provider;\n};\n\nconst getDefaultEIP6963SigningOptions = (\n customProvider?: Eip1193Provider,\n): AuthSigningOptions => ({\n getIdentifier: async (entropySourceId?: string): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n return await MESSAGE_SIGNING_SNAP.getPublicKey(provider, entropySourceId);\n },\n signMessage: async (\n message: string,\n entropySourceId?: string,\n ): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n assertMessageStartsWithMetamask(message);\n return await MESSAGE_SIGNING_SNAP.signMessage(\n provider,\n message,\n entropySourceId,\n );\n },\n});\n\nexport class SRPJwtBearerAuth implements IBaseAuth {\n readonly #config: AuthConfig;\n\n readonly #options: {\n storage: AuthStorageOptions;\n signing: AuthSigningOptions;\n };\n\n readonly #metametrics?: MetaMetricsAuth;\n\n // Map to store ongoing login promises by entropySourceId\n readonly #ongoingLogins = new Map<\n string | undefined,\n Promise<LoginResponse>\n >();\n\n // Default cooldown when 429 has no Retry-After header\n readonly #cooldownDefaultMs: number;\n\n // Maximum number of login retries on rate limit errors\n readonly #maxLoginRetries: number;\n\n #customProvider?: Eip1193Provider;\n\n constructor(\n config: AuthConfig & { type: AuthType.SRP },\n options: JwtBearerAuth_SRP_Options & {\n customProvider?: Eip1193Provider;\n metametrics?: MetaMetricsAuth;\n },\n ) {\n this.#config = config;\n this.#customProvider = options.customProvider;\n this.#options = {\n storage: options.storage,\n signing:\n options.signing ??\n getDefaultEIP6963SigningOptions(this.#customProvider),\n };\n this.#metametrics = options.metametrics;\n\n // Apply rate limit retry config if provided\n this.#cooldownDefaultMs =\n options.rateLimitRetry?.cooldownDefaultMs ?? 10000;\n this.#maxLoginRetries = options.rateLimitRetry?.maxLoginRetries ?? 1;\n }\n\n setCustomProvider(provider: Eip1193Provider) {\n this.#customProvider = provider;\n this.#options.signing = getDefaultEIP6963SigningOptions(provider);\n }\n\n // TODO: might be easier to keep entropySourceId as a class param and use multiple SRPJwtBearerAuth instances where needed\n async getAccessToken(entropySourceId?: string): Promise<string> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.token.accessToken;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.token.accessToken;\n }\n\n async getUserProfile(entropySourceId?: string): Promise<UserProfile> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.profile;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.profile;\n }\n\n async getIdentifier(entropySourceId?: string): Promise<string> {\n return await this.#options.signing.getIdentifier(entropySourceId);\n }\n\n async getUserProfileLineage(\n entropySourceId?: string,\n ): Promise<UserProfileLineage> {\n const accessToken = await this.getAccessToken(entropySourceId);\n return await getUserProfileLineage(this.#config.env, accessToken);\n }\n\n async signMessage(\n message: string,\n entropySourceId?: string,\n ): Promise<string> {\n return await this.#options.signing.signMessage(message, entropySourceId);\n }\n\n async isSnapConnected(): Promise<boolean> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n if (!provider) {\n return false;\n }\n\n const isConnected = await isSnapConnected(provider);\n return isConnected;\n }\n\n async connectSnap(): Promise<string> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n\n const res = await connectSnap(provider);\n return res;\n }\n\n // convert expiresIn from seconds to milliseconds and use 90% of expiresIn\n async #getAuthSession(\n entropySourceId?: string,\n ): Promise<LoginResponse | null> {\n const auth = await this.#options.storage.getLoginResponse(entropySourceId);\n if (!validateLoginResponse(auth)) {\n return null;\n }\n\n const currentTime = Date.now();\n const sessionAge = currentTime - auth.token.obtainedAt;\n const refreshThreshold = auth.token.expiresIn * 1000 * 0.9;\n\n if (sessionAge < refreshThreshold) {\n return auth;\n }\n return null;\n }\n\n async #login(entropySourceId?: string): Promise<LoginResponse> {\n // Use a deferred login to avoid race conditions\n return await this.#deferredLogin(entropySourceId);\n }\n\n async #performLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Nonce\n const publicKey = await this.getIdentifier(entropySourceId);\n const nonceRes = await getNonce(publicKey, this.#config.env);\n\n const rawMessage = this.#createSrpLoginRawMessage(\n nonceRes.nonce,\n publicKey,\n );\n const signature = await this.signMessage(rawMessage, entropySourceId);\n\n // Authenticate\n const authResponse = await authenticate(\n rawMessage,\n signature,\n this.#config.type,\n this.#config.env,\n this.#metametrics,\n );\n\n // Authorize\n const tokenResponse = await authorizeOIDC(\n authResponse.token,\n this.#config.env,\n this.#config.platform,\n );\n\n // Save\n const result: LoginResponse = {\n profile: authResponse.profile,\n token: tokenResponse,\n };\n\n await this.#options.storage.setLoginResponse(result, entropySourceId);\n\n return result;\n }\n\n async #deferredLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Check if there's already an ongoing login for this entropySourceId\n const existingLogin = this.#ongoingLogins.get(entropySourceId);\n if (existingLogin) {\n return existingLogin;\n }\n\n // Create a new login promise\n const loginPromise = this.#loginWithRetry(entropySourceId);\n\n // Store the promise in the map\n this.#ongoingLogins.set(entropySourceId, loginPromise);\n\n try {\n // Wait for the login to complete\n return await loginPromise;\n } finally {\n // Always clean up the ongoing login promise when done\n this.#ongoingLogins.delete(entropySourceId);\n }\n }\n\n async #loginWithRetry(entropySourceId?: string): Promise<LoginResponse> {\n // Allow max attempts: initial + maxLoginRetries on 429\n for (let attempt = 0; attempt < 1 + this.#maxLoginRetries; attempt += 1) {\n try {\n return await this.#performLogin(entropySourceId);\n } catch (e) {\n // Only retry on rate-limit (429) errors\n if (!RateLimitedError.isRateLimitError(e)) {\n throw e;\n }\n\n // If we've exhausted attempts, rethrow\n if (attempt >= this.#maxLoginRetries) {\n throw e;\n }\n\n // Wait for Retry-After or default cooldown\n const waitMs = e.retryAfterMs ?? this.#cooldownDefaultMs;\n await timeUtils.delay(waitMs);\n\n // Loop continues to retry\n }\n }\n\n // Should never reach here due to loop logic, but TypeScript needs a return\n throw new Error('Unexpected: login loop exhausted without result');\n }\n\n #createSrpLoginRawMessage(\n nonce: string,\n publicKey: string,\n ): `metamask:${string}:${string}` {\n return `metamask:${nonce}:${publicKey}` as const;\n }\n}\n"]}
1
+ {"version":3,"file":"flow-srp.mjs","sourceRoot":"","sources":["../../../src/sdk/authentication-jwt-bearer/flow-srp.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Eip1193Provider } from 'ethers';\n\nimport type { MetaMetricsAuth } from '../../shared/types/services';\nimport { ValidationError, RateLimitedError } from '../errors';\nimport { getMetaMaskProviderEIP6963 } from '../utils/eip-6963-metamask-provider';\nimport {\n MESSAGE_SIGNING_SNAP,\n assertMessageStartsWithMetamask,\n connectSnap,\n isSnapConnected,\n} from '../utils/messaging-signing-snap-requests';\nimport { validateLoginResponse } from '../utils/validate-login-response';\nimport {\n authenticate,\n authorizeOIDC,\n getNonce,\n getUserProfileLineage,\n pairProfiles,\n} from './services';\nimport type { PairProfilesResponse } from './services';\nimport type {\n AuthConfig,\n AuthSigningOptions,\n AuthStorageOptions,\n AuthType,\n IBaseAuth,\n LoginResponse,\n UserProfile,\n UserProfileLineage,\n} from './types';\nimport { computeIdentifierId } from './utils/identifier';\nimport * as timeUtils from './utils/time';\n\ntype JwtBearerAuth_SRP_Options = {\n storage: AuthStorageOptions;\n signing?: AuthSigningOptions;\n rateLimitRetry?: {\n cooldownDefaultMs?: number; // default cooldown when 429 has no Retry-After\n maxLoginRetries?: number; // maximum number of login retries on rate limit\n };\n};\n\nconst getDefaultEIP6963Provider = async () => {\n const provider = await getMetaMaskProviderEIP6963();\n if (!provider) {\n throw new ValidationError('No MetaMask wallet connected');\n }\n return provider;\n};\n\nconst getDefaultEIP6963SigningOptions = (\n customProvider?: Eip1193Provider,\n): AuthSigningOptions => ({\n getIdentifier: async (entropySourceId?: string): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n return await MESSAGE_SIGNING_SNAP.getPublicKey(provider, entropySourceId);\n },\n signMessage: async (\n message: string,\n entropySourceId?: string,\n ): Promise<string> => {\n const provider = customProvider ?? (await getDefaultEIP6963Provider());\n assertMessageStartsWithMetamask(message);\n return await MESSAGE_SIGNING_SNAP.signMessage(\n provider,\n message,\n entropySourceId,\n );\n },\n});\n\nexport class SRPJwtBearerAuth implements IBaseAuth {\n readonly #config: AuthConfig;\n\n readonly #options: {\n storage: AuthStorageOptions;\n signing: AuthSigningOptions;\n };\n\n readonly #metametrics?: MetaMetricsAuth;\n\n // Map to store ongoing login promises by entropySourceId\n readonly #ongoingLogins = new Map<\n string | undefined,\n Promise<LoginResponse>\n >();\n\n // Default cooldown when 429 has no Retry-After header\n readonly #cooldownDefaultMs: number;\n\n // Maximum number of login retries on rate limit errors\n readonly #maxLoginRetries: number;\n\n #customProvider?: Eip1193Provider;\n\n constructor(\n config: AuthConfig & { type: AuthType.SRP },\n options: JwtBearerAuth_SRP_Options & {\n customProvider?: Eip1193Provider;\n metametrics?: MetaMetricsAuth;\n },\n ) {\n this.#config = config;\n this.#customProvider = options.customProvider;\n this.#options = {\n storage: options.storage,\n signing:\n options.signing ??\n getDefaultEIP6963SigningOptions(this.#customProvider),\n };\n this.#metametrics = options.metametrics;\n\n // Apply rate limit retry config if provided\n this.#cooldownDefaultMs =\n options.rateLimitRetry?.cooldownDefaultMs ?? 10000;\n this.#maxLoginRetries = options.rateLimitRetry?.maxLoginRetries ?? 1;\n }\n\n setCustomProvider(provider: Eip1193Provider) {\n this.#customProvider = provider;\n this.#options.signing = getDefaultEIP6963SigningOptions(provider);\n }\n\n // TODO: might be easier to keep entropySourceId as a class param and use multiple SRPJwtBearerAuth instances where needed\n async getAccessToken(entropySourceId?: string): Promise<string> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.token.accessToken;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.token.accessToken;\n }\n\n async getUserProfile(entropySourceId?: string): Promise<UserProfile> {\n const session = await this.#getAuthSession(entropySourceId);\n if (session) {\n return session.profile;\n }\n\n const loginResponse = await this.#login(entropySourceId);\n return loginResponse.profile;\n }\n\n async getIdentifier(entropySourceId?: string): Promise<string> {\n return await this.#options.signing.getIdentifier(entropySourceId);\n }\n\n async getUserProfileLineage(\n entropySourceId?: string,\n ): Promise<UserProfileLineage> {\n const accessToken = await this.getAccessToken(entropySourceId);\n return await getUserProfileLineage(this.#config.env, accessToken);\n }\n\n async pairSrpProfiles(\n accessTokens: string[],\n authAccessToken: string,\n ): Promise<PairProfilesResponse> {\n return await pairProfiles(accessTokens, authAccessToken, this.#config.env);\n }\n\n async signMessage(\n message: string,\n entropySourceId?: string,\n ): Promise<string> {\n return await this.#options.signing.signMessage(message, entropySourceId);\n }\n\n async isSnapConnected(): Promise<boolean> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n if (!provider) {\n return false;\n }\n\n const isConnected = await isSnapConnected(provider);\n return isConnected;\n }\n\n async connectSnap(): Promise<string> {\n const provider =\n this.#customProvider ?? (await getDefaultEIP6963Provider());\n\n const res = await connectSnap(provider);\n return res;\n }\n\n // convert expiresIn from seconds to milliseconds and use 90% of expiresIn\n async #getAuthSession(\n entropySourceId?: string,\n ): Promise<LoginResponse | null> {\n const auth = await this.#options.storage.getLoginResponse(entropySourceId);\n if (!validateLoginResponse(auth)) {\n return null;\n }\n\n const currentTime = Date.now();\n const sessionAge = currentTime - auth.token.obtainedAt;\n const refreshThreshold = auth.token.expiresIn * 1000 * 0.9;\n\n if (sessionAge < refreshThreshold) {\n return auth;\n }\n return null;\n }\n\n async #login(entropySourceId?: string): Promise<LoginResponse> {\n // Use a deferred login to avoid race conditions\n return await this.#deferredLogin(entropySourceId);\n }\n\n async #performLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Nonce\n const publicKey = await this.getIdentifier(entropySourceId);\n const nonceRes = await getNonce(publicKey, this.#config.env);\n\n const rawMessage = this.#createSrpLoginRawMessage(\n nonceRes.nonce,\n publicKey,\n );\n const signature = await this.signMessage(rawMessage, entropySourceId);\n\n // Authenticate\n const authResponse = await authenticate(\n rawMessage,\n signature,\n this.#config.type,\n this.#config.env,\n this.#metametrics,\n );\n\n // Resolve original profileId from aliases.\n // This is done mainly to preserve the original profileId for storage key derivation\n // until we migrate to the canonical profileId storage system.\n const canonicalProfileId = authResponse.profile.profileId;\n const profile = { ...authResponse.profile };\n\n if (authResponse.profileAliases?.length > 0) {\n const targetIdentifierId = computeIdentifierId(\n publicKey,\n this.#config.env,\n );\n\n const targetAlias = authResponse.profileAliases.find((alias) =>\n alias.identifierIds.some((id) => id.id === targetIdentifierId),\n );\n\n if (targetAlias) {\n profile.profileId = targetAlias.aliasProfileId;\n }\n }\n\n profile.canonicalProfileId = canonicalProfileId;\n\n // Authorize\n const tokenResponse = await authorizeOIDC(\n authResponse.token,\n this.#config.env,\n this.#config.platform,\n );\n\n // Save\n const result: LoginResponse = {\n profile,\n token: tokenResponse,\n };\n\n await this.#options.storage.setLoginResponse(result, entropySourceId);\n\n return result;\n }\n\n async #deferredLogin(entropySourceId?: string): Promise<LoginResponse> {\n // Check if there's already an ongoing login for this entropySourceId\n const existingLogin = this.#ongoingLogins.get(entropySourceId);\n if (existingLogin) {\n return existingLogin;\n }\n\n // Create a new login promise\n const loginPromise = this.#loginWithRetry(entropySourceId);\n\n // Store the promise in the map\n this.#ongoingLogins.set(entropySourceId, loginPromise);\n\n try {\n // Wait for the login to complete\n return await loginPromise;\n } finally {\n // Always clean up the ongoing login promise when done\n this.#ongoingLogins.delete(entropySourceId);\n }\n }\n\n async #loginWithRetry(entropySourceId?: string): Promise<LoginResponse> {\n // Allow max attempts: initial + maxLoginRetries on 429\n for (let attempt = 0; attempt < 1 + this.#maxLoginRetries; attempt += 1) {\n try {\n return await this.#performLogin(entropySourceId);\n } catch (e) {\n // Only retry on rate-limit (429) errors\n if (!RateLimitedError.isRateLimitError(e)) {\n throw e;\n }\n\n // If we've exhausted attempts, rethrow\n if (attempt >= this.#maxLoginRetries) {\n throw e;\n }\n\n // Wait for Retry-After or default cooldown\n const waitMs = e.retryAfterMs ?? this.#cooldownDefaultMs;\n await timeUtils.delay(waitMs);\n\n // Loop continues to retry\n }\n }\n\n // Should never reach here due to loop logic, but TypeScript needs a return\n throw new Error('Unexpected: login loop exhausted without result');\n }\n\n #createSrpLoginRawMessage(\n nonce: string,\n publicKey: string,\n ): `metamask:${string}:${string}` {\n return `metamask:${nonce}:${publicKey}` as const;\n }\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUserProfileLineage = exports.authenticate = exports.authorizeOIDC = exports.getNonce = exports.pairIdentifiers = exports.PROFILE_LINEAGE_URL = exports.SIWE_LOGIN_URL = exports.SRP_LOGIN_URL = exports.OIDC_TOKEN_URL = exports.PAIR_IDENTIFIERS = exports.NONCE_URL = void 0;
3
+ exports.getUserProfileLineage = exports.authenticate = exports.authorizeOIDC = exports.getNonce = exports.pairProfiles = exports.pairIdentifiers = exports.PROFILE_LINEAGE_URL = exports.PAIR_PROFILES_URL = exports.SIWE_LOGIN_URL = exports.SRP_LOGIN_URL = exports.OIDC_TOKEN_URL = exports.PAIR_IDENTIFIERS = exports.NONCE_URL = void 0;
4
4
  const env_1 = require("../../shared/env.cjs");
5
5
  const constants_1 = require("../constants.cjs");
6
6
  const errors_1 = require("../errors.cjs");
@@ -112,6 +112,8 @@ const SRP_LOGIN_URL = (env) => `${(0, env_1.getEnvUrls)(env).authApiUrl}/api/v2/
112
112
  exports.SRP_LOGIN_URL = SRP_LOGIN_URL;
113
113
  const SIWE_LOGIN_URL = (env) => `${(0, env_1.getEnvUrls)(env).authApiUrl}/api/v2/siwe/login`;
114
114
  exports.SIWE_LOGIN_URL = SIWE_LOGIN_URL;
115
+ const PAIR_PROFILES_URL = (env) => `${(0, env_1.getEnvUrls)(env).authApiUrl}/api/v2/profile/pair`;
116
+ exports.PAIR_PROFILES_URL = PAIR_PROFILES_URL;
115
117
  const PROFILE_LINEAGE_URL = (env) => `${(0, env_1.getEnvUrls)(env).authApiUrl}/api/v2/profile/lineage`;
116
118
  exports.PROFILE_LINEAGE_URL = PROFILE_LINEAGE_URL;
117
119
  const getAuthenticationUrl = (authType, env) => {
@@ -125,6 +127,13 @@ const getAuthenticationUrl = (authType, env) => {
125
127
  throw new errors_1.ValidationError(`Invalid AuthType: ${authType} - unable to create Auth URL`);
126
128
  }
127
129
  };
130
+ const parseProfileAliases = (raw) => {
131
+ return raw.map((alias) => ({
132
+ aliasProfileId: alias.alias_profile_id,
133
+ canonicalProfileId: alias.canonical_profile_id,
134
+ identifierIds: alias.identifier_ids ?? [],
135
+ }));
136
+ };
128
137
  /**
129
138
  * Pair multiple identifiers under a single profile
130
139
  *
@@ -158,6 +167,47 @@ async function pairIdentifiers(nonce, logins, accessToken, env) {
158
167
  }
159
168
  }
160
169
  exports.pairIdentifiers = pairIdentifiers;
170
+ /**
171
+ * Pair multiple profiles using their OIDC access tokens.
172
+ * Idempotent — calling with already-paired tokens is a no-op.
173
+ *
174
+ * @param accessTokens - Two or more OIDC access tokens to pair
175
+ * @param authAccessToken - A valid access token for the Authorization header
176
+ * @param env - server environment
177
+ * @returns The pair response containing the canonical profile and aliases
178
+ */
179
+ async function pairProfiles(accessTokens, authAccessToken, env) {
180
+ const pairUrl = new URL((0, exports.PAIR_PROFILES_URL)(env));
181
+ try {
182
+ const response = await fetch(pairUrl, {
183
+ method: 'POST',
184
+ headers: {
185
+ 'Content-Type': 'application/json',
186
+ Authorization: `Bearer ${authAccessToken}`,
187
+ },
188
+ body: JSON.stringify({
189
+ jwts: accessTokens,
190
+ }),
191
+ });
192
+ if (!response.ok) {
193
+ return await throwServiceError(response, 'Failed to pair profiles', errors_1.PairError);
194
+ }
195
+ const pairResponse = await response.json();
196
+ return {
197
+ profile: {
198
+ identifierId: pairResponse.profile.identifier_id,
199
+ metaMetricsId: pairResponse.profile.metametrics_id ?? '',
200
+ profileId: pairResponse.profile.profile_id,
201
+ canonicalProfileId: pairResponse.profile.profile_id,
202
+ },
203
+ profileAliases: parseProfileAliases(pairResponse.profile_aliases ?? []),
204
+ };
205
+ }
206
+ catch (error) {
207
+ return await throwServiceError(error, 'Failed to pair profiles', errors_1.PairError);
208
+ }
209
+ }
210
+ exports.pairProfiles = pairProfiles;
161
211
  /**
162
212
  * Service to Get Nonce for JWT Bearer Flow
163
213
  *
@@ -240,6 +290,9 @@ async function authenticate(rawMessage, signature, authType, env, metametrics) {
240
290
  method: 'POST',
241
291
  headers: {
242
292
  'Content-Type': 'application/json',
293
+ ...(authType === types_1.AuthType.SRP
294
+ ? { 'X-MetaMask-Profile-Pairing': 'enabled' }
295
+ : {}),
243
296
  },
244
297
  body: JSON.stringify({
245
298
  signature,
@@ -265,7 +318,9 @@ async function authenticate(rawMessage, signature, authType, env, metametrics) {
265
318
  identifierId: loginResponse.profile.identifier_id,
266
319
  metaMetricsId: loginResponse.profile.metametrics_id,
267
320
  profileId: loginResponse.profile.profile_id,
321
+ canonicalProfileId: loginResponse.profile.profile_id,
268
322
  },
323
+ profileAliases: parseProfileAliases(loginResponse.profile_aliases ?? []),
269
324
  };
270
325
  }
271
326
  catch (error) {