Skip to content

Conversation

@adamjmcgrath
Copy link
Contributor

@adamjmcgrath adamjmcgrath commented Oct 6, 2025

Changes

Add support for Connected Accounts to SPA JS:

  • Bump SPA-JS to include Add support for connected accounts auth0-spa-js#1422
  • Add a new connectAccountWithRedirect method that redirects the application to the /connect endpoint on the auth server (similar mechanics to the logging in with the /authorize endpoint)
  • Update the playground to enabled testing Connected Accounts
image

References

https://auth0team.atlassian.net/browse/AGAI-157

Testing

Manual testing steps and demo video are in ESD-52475

  • This change adds unit test coverage
  • This change adds integration test coverage
    (integration tests are not possible since oidc-provider does not support the proprietary Auth0 connect flow)
  • This change has been tested on the latest version of the platform/language

Checklist

@adamjmcgrath adamjmcgrath force-pushed the connected-accounts branch 6 times, most recently from af7a728 to caffd4d Compare October 7, 2025 15:22
{},
document.title,
appState?.returnTo ?? window.location.pathname
appState!.returnTo ?? window.location.pathname
Copy link
Contributor Author

@adamjmcgrath adamjmcgrath Oct 8, 2025

Choose a reason for hiding this comment

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

There is always an appState now (with response_type) - but if I make it a required argument for defaultOnRedirectCallback it may cause TS compilation errors for people doing https://github.com/auth0/auth0-react/blob/main/examples/cra-react-router/src/index.tsx#L17

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm importing the actual Auth0Client into the tests (to get ResponseType) so we need the same as https://github.com/auth0/auth0-spa-js/blob/main/jest.environment.js#L17-L18

package.json Outdated
},
"dependencies": {
"@auth0/auth0-spa-js": "^2.5.0"
"@auth0/auth0-spa-js": "file:auth0-auth0-spa-js-2.6.0-connected-accounts.tgz"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will update this PR when auth0/auth0-spa-js#1422 gets shipped

@adamjmcgrath adamjmcgrath marked this pull request as ready for review October 14, 2025 14:22
@adamjmcgrath adamjmcgrath requested a review from a team as a code owner October 14, 2025 14:22
@gyaneshgouraw-okta
Copy link
Contributor

@claude

@github-actions
Copy link

github-actions bot commented Oct 15, 2025

Claude finished @gyaneshgouraw-okta's task —— View job


Review Complete

  • Read PR diff
  • Read project architecture documentation
  • Perform code quality review
  • Perform security review
  • Perform performance review
  • Provide overall assessment

Overall Assessment

❌ This PR requires attention to several type safety issues and edge case handling before merging. The core implementation is sound, but there are concerns around nullable handling, type casting without validation, and potential breaking changes to the onRedirectCallback API surface. Additionally, the regex pattern for URL parameter detection could be more precise to avoid false positives.

Key Issues:

  • Non-null assertion on potentially undefined appState (src/auth0-provider.tsx:130)
  • Missing validation before type casting result as ConnectedAccount (src/auth0-provider.tsx:178)
  • Overly broad regex pattern that could match unintended parameters (src/utils.tsx:3)
  • Breaking change to onRedirectCallback signature with response_type being added to appState
  • Insufficient test coverage for malformed responses

Job RunBranch: connected-accounts

{},
document.title,
appState?.returnTo ?? window.location.pathname
appState!.returnTo ?? window.location.pathname

Choose a reason for hiding this comment

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

The non-null assertion operator (!) is used here, but appState could still be undefined if handleRedirectCallback returns { appState: undefined }. This could cause runtime errors.

Consider using optional chaining instead:

appState?.returnTo ?? window.location.pathname

This also addresses the author's concern about making appState required breaking existing code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

{ appState: undefined }

This is not possible, because appState is always an object with at least response_type. I casted it here because I didn't want to write a test case for some unreachable code

let user: TUser | undefined;
if (hasAuthParams() && !skipRedirectCallback) {
const { appState } = await client.handleRedirectCallback();
const { appState = {}, response_type, ...result } = await client.handleRedirectCallback();

Choose a reason for hiding this comment

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

Type safety issue: The destructuring assumes response_type exists, but if it's missing from the response, appState.response_type will be set to undefined. This could lead to unexpected behavior if code assumes this property always has a value.

Consider adding validation or handling the case where response_type might be missing from the response.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In [email protected] response_type will always have a value

user = await client.getUser();
appState.response_type = response_type;
if (response_type === ResponseType.ConnectCode) {
appState.connectedAccount = result as ConnectedAccount;

Choose a reason for hiding this comment

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

Potential type safety issue: The cast result as ConnectedAccount assumes all remaining properties after destructuring match the ConnectedAccount type. If the response contains unexpected properties or is missing required properties, this could cause runtime issues.

Consider validating that result contains the expected properties (id, connection, access_type, created_at, expires_at) before casting, or using a type guard function.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's no benefit in runtime checks to confirm the my account api is returning what we expect, it would just make the client more brittle

onRedirectCallback,
});
renderHook(() => useContext(Auth0Context), {
wrapper,

Choose a reason for hiding this comment

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

Inconsistent test expectations: This test now expects response_type to be merged into the appState object, but this changes the API surface. Existing consumers of onRedirectCallback will receive a different object shape than before (with an additional response_type property).

While this might be intentional for the new feature, it's a breaking change that should be documented in the migration guide or release notes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Adding a new field to the return object of an api is not a breaking change, customers will only need to change their code if they're trying to implement a function that behaves the same as handleRedirectCallback - as we are doing here with the mock. (they may have to change their mocks if they're doing the same, but I don't believe this qualifies as a breaking change)

expires_at: '2024-01-02T00:00:00.000Z',
}
clientMock.getUser.mockResolvedValue(user);
clientMock.handleRedirectCallback.mockResolvedValue({

Choose a reason for hiding this comment

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

Missing test coverage: There's no test case for when response_type is ResponseType.ConnectCode but the result object is malformed or missing expected properties. This edge case should be tested to ensure the code handles invalid responses gracefully.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We're not putting in any additional logic to handle this case (see #912 (comment)) - so there's nothing to test

import { OAuthError } from './errors';

const CODE_RE = /[?&]code=[^&]+/;
const CODE_RE = /[?&](?:connect_)?code=[^&]+/;

Choose a reason for hiding this comment

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

Regex pattern could match unintended parameters: The pattern (?:connect_)?code will match both code and connect_code, but it will also match any parameter starting with code (e.g., code_verifier, code_challenge).

Consider making the pattern more specific with word boundaries:

const CODE_RE = /[?&](?:connect_)?code(?:=|&|$)/;

Or more explicitly:

const CODE_RE = /[?&](?:connect_code|code)=[^&]+/;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No it wont
image

@adamjmcgrath adamjmcgrath merged commit faf6bf7 into main Oct 15, 2025
21 of 22 checks passed
@adamjmcgrath adamjmcgrath deleted the connected-accounts branch October 15, 2025 08:04
@adamjmcgrath adamjmcgrath mentioned this pull request Oct 15, 2025
gyaneshgouraw-okta pushed a commit that referenced this pull request Oct 15, 2025
**Added**
- Add support for connected accounts
[\#912](#912)
([adamjmcgrath](https://github.com/adamjmcgrath))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants