nhost / nhost-dart

Nhost Dart & Flutter packages
https://nhost.io
MIT License
90 stars 33 forks source link

resetPassword: The value of "options.redirectTo" is not allowed #96

Closed diegonc closed 1 year ago

diegonc commented 1 year ago

I'm getting this exception while trying to reset the password of a user:

E/flutter (12035): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: ApiException: apiUrl=https://jixoaoumojenusgmwtfd.nhost.run/v1/auth/user/password/reset, statusCode=400, responseBody={status: 400, message: The value of "options.redirectTo" is not allowed., error: invalid-request}
E/flutter (12035): #0      ApiClient._handleResponse (package:nhost_sdk/src/api/api_client.dart:281:7)
E/flutter (12035): #1      ApiClient.send (package:nhost_sdk/src/api/api_client.dart:240:12)
E/flutter (12035): <asynchronous suspension>
E/flutter (12035): #2      AuthClient.resetPassword (package:nhost_sdk/src/auth_client.dart:450:5)
E/flutter (12035): <asynchronous suspension>
E/flutter (12035): #3      LoginEmailForgotController.submit (package:app/pages/login_email_forgot.dart:23:5)
E/flutter (12035): <asynchronous suspension>
E/flutter (12035):

The code (at trace # 3) is the following submit method in my controller:

  Future<void> submit() async {
    NHostController nhc = Get.find();
    await nhc.client.auth.resetPassword(
        email: emailCtrl.value.text.trim(),
        redirectTo: '/app/login_email_forgot_change');
  }

I think the code already complies with the usage of redirectTo as specified in the JavaScript reference.

But for some reason it's still failing. The logs at NHost dashboard are very limited and not quite useful:

2022-12-22 16:04:27 | hasura-auth | {"latencyInNs":4000000,"level":"info","message":"POST /user/password/reset 400 4ms","method":"POST","statusCode":400,"url":"/user/password/reset"}

2022-12-22 16:03:25 | hasura-auth | {"latencyInNs":16000000,"level":"info","message":"POST /user/password/reset 400 16ms","method":"POST","statusCode":400,"url":"/user/password/reset"}

Any pointers?

vipafattal commented 1 year ago

I am facing the same issue here

mhadaily commented 1 year ago

This is not a bug. You need to pass your clientUrl along with the redirect. The Dart SDK doesn't add anything to redirectTo automatically. Therefore you need to pass your entire URL.

You can configure that in Nhost dashboard -> settings -> authentication

alt text

So, if you change redirectTo: "http://localhost:3000/app/login_email_forgot_change" it should work. Consider replacing "http://localhost:3000" with your client URL.

you full example become

 Future<void> submit() async {
    NHostController nhc = Get.find();
    await nhc.client.auth.resetPassword(
        email: emailCtrl.value.text.trim(),
        redirectTo: '$clientUrl/app/login_email_forgot_change');
  }

btw, we now have a new version "4.0.0-dev.7" where you can get the newest SDK and changes including subdomain together with so many bug fixes.

diegonc commented 1 year ago

My Client URL looks like https://{domain}/app/auth_complete to forward the social authentication flow to the correct screen.

I cannot use https://{domain} as that would not have the page and redirect to something like https://{domain}/?refreshToken=....

What I'm currently doing is multiplex the auth_complete route by the type=passwordReset parameter which is only present in password reset requests and not in the social login flow.

mhadaily commented 1 year ago

Is this only a Dart SDK or is it out of the SDK and going to the Nhost architecture design? I need to follow up on this with @elitan or the team.

If you have more insight here, please share. Thanks.

plmercereau commented 1 year ago

Hello @diegonc,

If you set the redirectTo option to https://{domain}/app/auth_complete, then the redirection will be:

https://{domain}/app/auth_complete?refreshToken=...

Is this what you meant?

You can set your client URL to https://{domain}. The authentication service will any route that starts with https://{domain}.

Does it answer your question?

diegonc commented 1 year ago

If you set the redirectTo option to https://{domain}/app/auth_complete, then the redirection will be:

https://{domain}/app/auth_complete?refreshToken=...

If I set redirectTo option to https://{domain}/app/login_email_forgot_change then it only works when Client URL in the NHost dashboard is set to https://{domain} (looks like a prefix check is made somewhere).

But I cannot set Client URL like that because the GitHub authentication will redirect to that URL ( https://{domain}?refreshToken=... ) instead of https://{domain}/app/auth_complete?refreshToken=....

So, to summarize:

Getting redirected to https://{domain} is troublesome because then the app will not open in response to the navigation.

mhadaily commented 1 year ago

mm,

why don't you make the Authorization callback URL on Github to https://{domain}/app/auth_complete same as clienturl on Nhost to https://{domain}/app/auth_complete both will be same! where after success it will redirect to the same URL that is your ClientURL in Nhost? in this case both Github will redirect to the same client URL that you have set on Nhost.

Am I missing something? The Dart SDK does not prefix anything to redirectTo , whatever you pass, it will be passed to server.

diegonc commented 1 year ago

why don't you make the Authorization callback URL on Github to https://{domain}/app/auth_complete same as clienturl on Nhost to https://{domain}/app/auth_complete both will be same! where after success it will redirect to the same URL that is your ClientURL in Nhost? in this case both Github will redirect to the same client URL that you have set on Nhost.

That's what I'm currently doing. But then, the resetPassword call cannot have a redirectTo parameter.

Am I missing something? The Dart SDK does not prefix anything to redirectTo , whatever you pass, it will be passed to server.

Correct, the Dart version of the SDK takes the redirectTo parameter as is. I think it's the NHost server that checks the redirectTo value against the Client URL and reject it if it is not prefixed by client url.

mhadaily commented 1 year ago

Alright, @elitan or @plmercereau Can you confirm the later? if the server does anything funky? This seems to be an issue from the server.

@diegonc if would be fantastic, if you can make a working example on Zapp.run that can be shown the issue.

diegonc commented 1 year ago

@diegonc if would be fantastic, if you can make a working example on Zapp.run that can be shown the issue.

I will try, but it seems to build for Web environment whereas I need deep linking on a mobile platform.

plmercereau commented 1 year ago

To clarify: the GitHub callback is not the redirectTo option, but the right Nhost endpoint as per defined in the dashboard in Settings -> Sign-in methods -> GitHub -> Redirect URL.

Here's what happens:

  1. the client goes to {nhost-backend}/signin/provider/github?redirectTo={client_url}/path
  2. the auth service (hasura-auth) starts a session (including the redirectTo option), and redirects to GitHub
  3. GitHub authenticates the user and redirects to {nhost-backend}/signin/provider/github/callback
  4. the auth service completes the authentication/registration of the user and redirects to the redirectTo options with the refresh token: {client_url}/path?refreshToken=xxx

Here's a link to the hasura-auth documentation.

diegonc commented 1 year ago
  1. the client goes to {nhost-backend}/signin/provider/github?redirectTo={client_url}/path

Oh, I didn't know a redirectTo could be passed here. I was following the OAuth example for flutter where no parameter is passed. Will try in that way, Thanks!

diegonc commented 1 year ago

It worked. What I did was:

  1. Set Client URL to https://{domain} (at Settings -> Authentication of the Nhost dashboard)
  2. On social login, launch the following URL
    https://{nhost-backend}/v1/signin/provider/github?redirectTo=${Uri.encodeQueryComponent('https://{domain}/app/auth_complete)}
  3. On password change requests run the following code:
    await client.auth.resetPassword(
    email: emailCtrl.value.text.trim(),
    redirectTo: 'https://{domain}/app/login_email_forgot_change'
    );

I think this can be closed, as it's a mattter of gettiing the configuration right. No bug here.