Laravel 5.1 - Trying to Prevent 302 URL Redirect Using Auth Boilerplate as API

8.5k views Asked by At

I've setup an Ionic app to use Laravel 5.1 as an API. When I try to login, register, or email a reset password link using the boilerplate AuthController of Laravel the request sent via AngularJS ngResource to the associated RESTful endpoint is received, but it always does a 302 URL redirect to load a view before returning a 200 response from a different initiator with an error related to not not finding a view, which I can see occur in Chrome's network tab (see below for output). I would expect that the view wouldn't be found as I'm using Laravel as an API and there are no views except for an email template. What I'm trying to do is remove the redirect.

For example a forgotten password email request would go out (and the email is received with the reset link using the email template), and instead of a JSON response for that request a URL redirect occurs (code 302) and then a response 200 with an error that the view was not found:

** Error Response **

Sorry, the page you are looking for could not be found. 
NotFoundHttpException in RouteCollection.php).

Chrome Console - Network Tab

Name        Status Type         Initiator                               Size  Time
forgot      302    text/html    ionic.bundle.js:18526                   614 B   2.38 s  
localhost   200    xhr          http://project.dev/api/password/forgot  2.3 KB  2.00 ms 

What I would expect is:

Name        Status Type         Initiator                               Size  Time
forgot      200    text/html    ionic.bundle.js:18526                   614 B   2.38 s  

Which occurs if I use a route that doesn't use a the AuthController actions, and instead just returns a JSON response like this:

Route::post('email', function () {
    return response()->json([ 'message' => 'Send an email!' ], 200);
});

Laravel Routes

+--------+----------+------------------------------+----------------------+-------------------------------------------------------------+------------+
| Domain | Method   | URI                          | Name                 | Action                                                      | Middleware |
+--------+----------+------------------------------+----------------------+-------------------------------------------------------------+------------+
|        | GET|HEAD | test                         |                      | Closure                                                     |            |
|        | POST     | api/auth/login               |                      | Project\Http\Controllers\Auth\AuthController@postLogin     | guest      |
|        | GET|HEAD | api/auth/logout              |                      | Project\Http\Controllers\Auth\AuthController@getLogout     |            |
|        | POST     | api/auth/register            |                      | Project\Http\Controllers\Auth\AuthController@postRegister  | guest      |
|        | POST     | api/password/forgot          |                      | Project\Http\Controllers\Auth\PasswordController@postEmail | guest      |
|        | POST     | api/password/reset           |                      | Project\Http\Controllers\Auth\PasswordController@postReset | guest      |
+--------+----------+------------------------------+----------------------+-------------------------------------------------------------+------------+

So I looked through the different Auth related classes and traits and with some help found that I can overwrite postLogin, postRegister, postEmail, postReset, and getLogout routes by adding them to the AuthController. So for example postEmail now returns a response and is located in AuthController:

** postEmail Override in AuthController** This is a copy of the original postEmail method, with a change in the return statements.

public function postEmail(Request $request)
{
    $this->validate($request, [ 'email' => 'required|email' ]);

    $response = Password::sendResetLink($request->only('email'), function (Message $message) {
        $message->subject($this->getEmailSubject());
    });

    switch ($response) {
        case Password::RESET_LINK_SENT:
            return response()->json([ 'message' => trans($response) ], 200);

        case Password::INVALID_USER:
            return response()->json([ 'message' => trans($response) ], 400);
    }
}

But, with this and the others (postLogin, postRegister, postReset, and getLogout) overwritten in AuthController, and the redirects overwritten with JSON responses, for some reason the 302 URL redirect still occurs as if the changes I made to AuthController aren't being applied. Why isn't this working still?

4

There are 4 answers

0
mtpultz On BEST ANSWER

Reason for this occurring is:

  1. The postEmail and postReset functions do not belong in the AuthController where I accidentally pasted them along side postLogin and postRegister, they belong in the PasswordController (yeesh)
  2. Both controllers were missing a few dependencies after dropping a copy of the original methods into the controllers to override and change the redirects to JSON responses
  3. Also the guest middleware from the constructor in AuthController had to be removed to prevent the redirect to /home from occurring on Authentication

Now I don't have anymore 302 URL redirects occurring, and I'm a bit wiser...? :)

4
ThreeAccents On

you can return a json response.

public function register()
{
    // do what ever to register the user
    // then just return a json response

    return response()->json([
        'message' => 'user was registered'
    ]);
}

EDIT:

add this method to Http\Requests\Request:

public function response(array $errors)
{
    return new JsonResponse($errors, 422);
}

I think there might be a bug in Laravel 5.1 where its handling every request as a regular request and not an ajax request. That method should fix it, it did for me.

1
Pantelis Peslis On

You can override the redirectPath method of Illuminate\Foundation\Auth\RedirectsUsers trait.

public function redirectPath()
{
    return response()->json([
        'msg' => 'your custom message'
    ]);
}
0
Wenrui Zhao On

I think Ive got this problem.

Notice that there is a middleware loaded in app/Http/Kernel.php which names RedirectIfAuthenticated. It contains the logic about redirecting to the home controller. Just comment it, and it will be done.