dozed
dozed

Reputation: 192

Laravel 4 Basic Auth custom error

I'm using the 'HTTP Basic Authentication' feature of laravel. I want to customize the error message which is generated from laravel if the entered credentials are wrong.

Is it possible to catch the 401 Error which is generated when HTTP Auth fails?

Hope you can help me.

Regards

Upvotes: 1

Views: 3738

Answers (2)

Jeff Hertzler
Jeff Hertzler

Reputation: 41

Here's how I did it:

Route::filter('auth.basic', function()
{
    $message = [
        "error" => [
            "code" => 401,
            "message" => "Invalid Credentials"
        ]
    ];

    $headers = ['WWW-Authenticate' => 'Basic'];

    $response = Auth::basic();

    if (!is_null($response)) {

        return Response::json($message, 401, $headers);
    }
});

If you look in Illuminate\Auth\Guard you'll find the basic method that's called by Auth::basic(). It either returns null or a Response object via the getBasicResponse method.

/**
 * Attempt to authenticate using HTTP Basic Auth.
 *
 * @param  string  $field
 * @param  \Symfony\Component\HttpFoundation\Request  $request
 * @return \Symfony\Component\HttpFoundation\Response|null
 */
public function basic($field = 'email', Request $request = null)
{
    if ($this->check()) return;

    $request = $request ?: $this->getRequest();

    // If a username is set on the HTTP basic request, we will return out without
    // interrupting the request lifecycle. Otherwise, we'll need to generate a
    // request indicating that the given credentials were invalid for login.
    if ($this->attemptBasic($request, $field)) return;

    return $this->getBasicResponse();
}

Here's getBasicResponse:

/**
 * Get the response for basic authentication.
 *
 * @return \Symfony\Component\HttpFoundation\Response
 */
protected function getBasicResponse()
{
    $headers = array('WWW-Authenticate' => 'Basic');

    return new Response('Invalid credentials.', 401, $headers);
}

Here we finally have our 'Invalid credentials.' text that we're looking to change. We see it's just returning an instance of a Symphony response with a 401 status code and the Basic Auth header and null in all other occasions. So, we'll just check for a non-null result and if we get one, return our new response as shown above.

Also, if you want it to actually be stateless you should use:

Auth::onceBasic()

I don't know how future proof this method is, but it works as of Laravel 4.1.

Final results once again:

Route::filter('auth.basic', function()
{
    $message = [
        "error" => [
            "code" => 401,
            "message" => "Invalid Credentials"
        ]
    ];

    $headers = ['WWW-Authenticate' => 'Basic'];

    $response = Auth::onceBasic();

    if (!is_null($response)) {

        return Response::json($message, 401, $headers);
    }
});

Upvotes: 4

Andreyco
Andreyco

Reputation: 22872

Basic Auth

Try to capture 401 error and return cusom view?!

App::error(function($exception, $code)
{
    switch ($code)
    {
        case 401:
            return Response::view('errors.403', array(), 401);

        case 403:
            return Response::view('errors.403', array(), 403);

        case 404:
            return Response::view('errors.404', array(), 404);

        case 500:
            return Response::view('errors.500', array(), 500);

        default:
            return Response::view('errors.default', array(), $code);
    }
});





Using Auth library

I think, code is pretty straightforward and self explaining. Just to note, $errors variable is of type MessageBag and is available in views even if you don't set it explicitly! Which is great! :)

I used simple routing, place it into your controllers

app/routes.php

Route::get('auth', function()
{
    $creds = array(
        'email' => Input::get('email'),
        'password'  => Input::get('password'),
    );

    if ( ! Auth::attempt($creds))
    {
        $errors = new MessageBag;
        $errors->add('login', trans("Username and/or password invalid."));
        return Redirect::to('/')->withErrors($errors);
    }

    return Redirect::to('/protected/area');

});


Route::get('/', function(){
    return View::make('hello');
});



// app/views/hello.php
@if($errors->has('login'))
    {{ $errors->first('login') }}
@endif

Upvotes: 4

Related Questions