auth0/auth0-vue

loginWithRedirect returns invalid state with Capacitor Browser.open

Jeffrey-IKUU opened this issue · 14 comments

Checklist

  • The issue can be reproduced in the auth0-vue sample app (or N/A).
  • I have looked into the Readme, Examples, and FAQ and have not found a suitable solution or answer.
  • I have looked into the API documentation and have not found a suitable solution or answer.
  • I have searched the issues and have not found a suitable solution or answer.
  • I have searched the Auth0 Community forums and have not found a suitable solution or answer.
  • I agree to the terms within the Auth0 Code of Conduct.

Description

According to your migration guide from V1 to V2, buildAuthorizeURL is removed. The new suggested method (Browser.open) isn't working as intended.

Also see this link:
auth0/auth0-react#410 (comment)

buildAuthorizeURL was intended to work with frameworks like Capacitor. With the solution you've provided, the login screen will appear. When returning to my app after successfull login, I get an error "invalid state". When doing more research, and comparing the tokens that are interchanged during the login process, I found out that the Capacitor app loses focus when loginWithRedirect is opened. So, after returning to the app, all tokens are renewed, causing this "invalid state" error.

Please check this link for the full info of my issue:
https://community.auth0.com/t/invalid-state-on-capacitor-vue-when-using-browser-open/118195

Reproduction

Please, see my package.json and code at Auth0 forum:
https://community.auth0.com/t/invalid-state-on-capacitor-vue-when-using-browser-open/118195

Additional context

No response

auth0-vue version

2.3.0

Vue version

3.3.4

Which browsers have you tested in?

Chrome, Safari, Other

Hey @Jeffrey-IKUU, I just tried out Ionic Vue sample and I'm not able to reproduce this issue and login works as expected. I'm going to work on upgrading our sample to use newer versions capacitor dependencies like yours to see if the issue appears

@ewanharris on localhost everything seems to work, but that's most likely because the auth0 login page is opened in another tab, so the app stays active. On iOS, however, I keep on receiving this "invalid state" error.

Thanks for the clarification @Jeffrey-IKUU, I'm testing on an iOS simulator myself, that should reproduce the issue I believe?

@ewanharris I assume it would. If not, I can DM you with some pieces of our code?

If you're able to provide a minimal reproducible sample that would be great, if you're able to rework the existing sampleto match your application that would be good.

Our sample is focused on Ionic + Capacitor whereas based on your dependencies I don't think you're using Ionic so I'm curious if that difference could cause this.

@ewanharris I've created a stripped repository of our app (you're also invited). auth0 credentials are removed and should be changed to yours.

npm install, then ntl dev (to use functions, not neccessary).

On app.vue, onBeforeMount the app's checking if this is your first visit. If it is, it will redirect you to /tutorial. This route is set to views/tutorial.vue. Tutorias.vue contains a function called "mobileLogin", which contains the loginWithRedirect causing the error.

Inside app.vue you'll find the listener on "appUrlOpen".

I've removed all other pages, components, etc. as they are not needed for the repro.

Thanks for that @Jeffrey-IKUU, I'll start taking a look today and get back to you when I have some more info

@Jeffrey-IKUU, after checking it out there appears to be two things at play causing the issues:

  • Firstly, the usage of useCookiesForTransactions: true appears to be problematic for iOS, I believe this is down to an iOS platform difference that is causing issues with the app accessing the state cookies when returning back to the app. Setting this to false or removing it (it defaults to false) will solve the first issue of failing to find the required state data when returning to the app.
  • Secondly, it appears that loginWithRedirect is being called twice, once from tutorial.vue when ending the tutorial and then also in login.vue when the page mounts. This is causing two "transactions" to be created so that when returning to the app the state can be found, but does not match the expected state returned from login. This is ultimately expected due calling login twice.

For the first one, I'll look to see how we can update our quickstart guides to call out the useCookiesForTransactions incompatibility on iOS, the second one is more implementation based and might just be an error in the reduced app

Thank you for looking into it. I'm gonna explore your suggestions and see what I learn. I'll get back to you as soon as I have more info. Thanks!

Closing as it seems like everything was answered. We can always reopen if needed, just ping us!

@frederikprijck and @ewanharris the issue still occurs. We've deleted all extra loginWithRedirects, brought it back to one single call on the login page. We console.log the states on every moment in the app and the values are unchanged. Also on callback, the state matches the one created on mount.

@Jeffrey-IKUU I am not sure I understand. The issue as about invalid state, but you say the state matches? Can you elaborate how you verify that the state matches?

Additionally, are you using useCookiesForTransactions : true ?

@frederikprijck
CapApp.addListener(“appUrlOpen”, async ({ url }) => { console.log(‘handle url: ‘, url) if ( url.includes(“state”) && (url.includes(“code”) || url.includes(“error”)) ) { await handleRedirectCallback(url).then((user) => { console.log(‘Auth succesful’, user) }).catch((error) => { console.error(‘Auth failed’, error) }); } const deviceInfo = await Device.getInfo(); const deviceOS = deviceInfo.platform; // No-op on Android if (deviceOS == “ios”) { await Browser.close(); // Close the browser so we don’t have to press done. This is iOS only, Android breaks if it hits this line } });

This returns the console.error

@frederikprijck and yes, it seems that useCookiesForTransactions still was set to true. Setting it to false at least removed the "invalid state" error