As of new 2.x-dev social_auth has a feature to redirect user back to destination page on successful authentication. It should also have an error destination page. So, if any error occurs on login we can redirect back user to the origin page and not the `user.login` route.

A valid scenario here is:
During checkout process, we can have a login block as a checkout step. So this is a login panel inside checkout not the user login / register page. But a block which allows user to get login and continue the process.

So, When user tries social authentication and fails it should return back to checkout login page not the user login page.

Comments

miteshmap created an issue. See original summary.

miteshmap’s picture

Assigned: miteshmap » Unassigned
Status: Needs work » Needs review
StatusFileSize
new4.39 KB
miteshmap’s picture

StatusFileSize
new4.09 KB
miteshmap’s picture

Title: Set login error destination to allow users to redirect back to the origin page on scoial auth fail. » Set login error destination to allow users to redirect back to the origin page on social auth fail.
miteshmap’s picture

gvso’s picture

This looks like a valid thing to add. However, I wonder if this problem could not be solved by using events instead.

If we are to include something like this, we might want to allow options to redirect to the origin in successful or failed logins. Something that is more general. What do you think about allowing this to be the case?

gvso’s picture

Status: Needs review » Needs work

By the way, we might want to include these as options in the settings form then

miteshmap’s picture

If we are to include something like this, we might want to allow options to redirect to the origin in successful or failed logins.

@gvso IMHO, This part is already covered in current social_auth module, the social auth link supports "destination" query string param. So, if we pass the destination in social auth link, It redirects back to that path on successful login.

But that is not mentioned anywhere. Neither in settings or in README file. I think we need to cover that part.

So, the only thing that we need to do is, to add settings to allow user to redirect back to origin page when destination is used. What do you think about this?

gvso’s picture

Sorry, I think I'm not getting your point correctly.

to add settings to allow user to redirect back to origin page when destination is used

Are you saying that we need to provide a way to allow the destination parameter to be set to the origin?

For instance, the user is at /node/5 and tries to log in. Then, the destination would be set to /node/5

miteshmap’s picture

There are two things here:

  1. Destination link on successful login
  2. Error Destination link on error

Destination link is the next page after login, and error destination is the original page from where the login request is being made.

Sorry! I again considering a scenario of checkout process (And ignoring user login/register as it's working fine and no change needed there.):

  1. For a checkout login page, we need to place the social auth link block here.
  2. Now we use destination query string here, it is going to be the destination after successful login. (Which is already there in 2.x)
    • - when user comes on checkout login page it has the url like - /checkout/login?destination=/checkout/payment
    • - the social auth link on checkout login page for facebook (i.e.) now becomes - user/login/facebook?destination=/checkout/payment
  3. What about on fail? user should go back to checkout login page, Not the user login page.
  4. For this we can use HTTP_REFERER, and set it in session with login_error_destination key.
  5. the link goes to user/login/facebook path we store the HTTP_REFERER which is /checkout/login as login_error_destination.

so, when user authenticated successfully we redirect them to login_destination else on error redirect them to login_error_destination

gvso’s picture

Two things here:

  1. What about dispatching an event on authentication error? Implementers usually check that there are no errors in their callback methods. We can define a dispatchAuthenticationError method in Social Auth and call it in these cases. This will give the developer more flexibility in determining what exactly to do in a failed login.
  2. If we decide not to do the event approach, I would suggest a common method to handle login_destination and login_error_destination. I would like things to be as simple as possible in the implementer's side.
miteshmap’s picture

Status: Needs work » Needs review
StatusFileSize
new10.49 KB
gvso’s picture

Status: Needs review » Needs work
  1. +++ b/src/Controller/OAuth2ControllerBase.php
    @@ -112,6 +125,7 @@ class OAuth2ControllerBase extends ControllerBase {
    +                              EventDispatcherInterface $event_dispatcher,
    

    I'm concerned that this will break everything. We need backward compatibility as we did with $renderer.

  2. +++ b/src/Event/SocialAuthProviderEvent.php
    @@ -0,0 +1,92 @@
    +class socialAuthProviderEvent extends Event {
    

    Maybe ProviderRedirectEvent. Let's try to get rid of the SocialAuth prefix in most of our classes.

  3. +++ b/src/Event/SocialAuthProviderEvent.php
    @@ -0,0 +1,92 @@
    +  /**
    +   * Store error destination path where user should redirect when provider
    +   * Throws error.
    +   *
    +   * @param string $error_destination
    +   */
    +  public function setErrorDestination($error_destination) {
    +    $this->dataHandler->set('login_error_destination', $error_destination);
    +  }
    

    Do we need this? I wonder if the event listener can't just do the redirection if there's an error in provider.

gvso’s picture

I'm concerned that this will break everything. We need backward compatibility as we did with $renderer.

Another way to go about might be to use userAuthenticator to handle the error dispatching. This object already contains the event dispatcher

miteshmap’s picture

Another way to go about might be to use userAuthenticator to handle the error dispatching. This object already contains the event dispatcher

The class has the object protected, it will require a public helper method to use it outside the class.
Instead, I think we should inject the dependency inside OAuth2ControllerBase itself as optional, and if not passed, we'll use the service like the $renderer.

From, Comment #13 - third point.

Do we need this? I wonder if the event listener can't just do the redirection if there's an error in provider.

No we don't need that.
I'll remove all unnecessary methods from SocialAuthProviderEvent (ProviderRedirectEvent) and SocialAuthProviderErrorEvent (ProviderErrorEvent).

miteshmap’s picture

miteshmap’s picture

Status: Needs work » Needs review
gvso’s picture

Thanks!

+++ b/src/Controller/OAuth2ControllerBase.php
@@ -212,6 +230,25 @@ class OAuth2ControllerBase extends ControllerBase {
+  public function dispatchAuthenticationError($error = NULL) {
+    $event_object = new ProviderErrorEvent($this->dataHandler, $this->pluginId, $error ?? NULL);
+    $this->eventDispatcher->dispatch(SocialAuthEvents::PROVIDER_ERROR, $event_object);
+
+    if ($event_object->hasResponse()) {
+      return $event_object->getResponse();
+    }
+    return NULL;
+  }
The class has the object protected, it will require a public helper method to use it outside the class.
Instead, I think we should inject the dependency inside OAuth2ControllerBase itself as optional, and if not passed, we'll use the service like the $renderer.

Why can't this code be in UserAuthenticator? Injecting the event dispatcher service is a pain for two reasons. First, we'll need to update all implementers. Second, I think it feels more natural to just have it in UserAuthenticator since it is an error with authentication.

Of course, doing so wouldn't allow us to dispatch an event before redirecting, but I'm not sure why you would need one. Any thoughts?

The other option is to have a getEventDispatcher in UserAuthenticator, so we can dispatch an event before redirecting without injecting the service.

miteshmap’s picture

Of course, doing so wouldn't allow us to dispatch an event before redirecting, but I'm not sure why you would need one. Any thoughts?

Only reason to do this is, to use "destination" from request. https://git.drupalcode.org/project/social_auth/blob/8.x-2.x/src/Controller/OAuth2ControllerBase.php#L182

Updating that too, creating dispatchBeforeRedirect helper method inside UserAuthenticator. we will use that here in-place of,

+        $event = new ProviderRedirectEvent($this->dataHandler, $this->pluginId, $destination ?? NULL);
+        $this->eventDispatcher->dispatch(SocialAuthEvents::BEFORE_PROVIDER_REDIRECT, $event);
miteshmap’s picture

gvso’s picture

Would you mind sharing an interdiff? Also, some documentation would be nice for this issue. We can create a new doc page for 'Handling authentication errors' or something similar, like this page.

miteshmap’s picture

StatusFileSize
new5.48 KB

Here is the interdiff, Do you want me to add the documentation here? OR I can add details in discussion at - https://www.drupal.org/node/2971213/discuss

gvso’s picture

Please add a new documentation page under the Social Auth documentation guide. This will also help me test the changes and we'll have documentation for this. Even if we decide to change some parts of your patch, I believe the new events would work anyways.

Thank you for working on this! I would love to include it in the next release

gvso’s picture

Title: Set login error destination to allow users to redirect back to the origin page on social auth fail. » Dispatch events for handling authentication errors in provider
Issue summary: View changes

  • gvso committed 27930c3 on 8.x-2.x
    Issue #3033749 by miteshmap: Dispatch events for handling authentication...
gvso’s picture

Status: Needs review » Fixed

I made a few changes regarding the events' names and constants. I also updated the documention and will add the example in social_api_examples.

Thank you so much! This was an awesome job!

miteshmap’s picture

Nice job on naming correction and document. Thank you so much @gvso for accepting this feature request on priority.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.