Courses

Build Laravel API for Car Parking App: Step-By-Step

User Area: User Login

Now, in the same fashion, let's generate a Controller for the login mechanism:

php artisan make:controller Api/V1/Auth/LoginController

This will be the new route, in the routes/api.php file:

Route::post('auth/login', Auth\LoginController::class);

Again, the route prefix and Controller namespace will come automatically from the other logic we've discussed earlier, for RegisterController.

Inside the Controller, we log the user in and return the Sanctum token, similarly to the Registration function:

app/Http/Controllers/Api/V1/Auth/LoginController.php:

namespace App\Http\Controllers\Api\V1\Auth;
 
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;
 
class LoginController extends Controller
{
public function __invoke(Request $request)
{
$request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
 
$user = User::where('email', $request->email)->first();
 
if (! $user || ! Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
 
$device = substr($request->userAgent() ?? '', 0, 255);
$expiresAt = $request->remember ? null : now()->addMinutes(config('session.lifetime'));
 
return response()->json([
'access_token' => $user->createToken($device, expiresAt: $expiresAt)->plainTextToken,
], Response::HTTP_CREATED);
}
}

I think the logic is pretty clear here: we validate the data, get the user by email.

If there's no user or wrong password - we throw the validation exception, which automatically is transformed to this structure with the HTTP Status code 422:

Laravel API Login

If the login attempt is successful, we return the newly generated Laravel Sanctum token for the future requests.

Laravel API Login

The new thing here is that we implement the "remember me" functionality: if the $request->remember is present and true, then we set the additional expiresAt parameter in the Sanctum createToken() method.

Now, time to create the endpoints with the logged in user?

Previous: User Area: Register New User
avatar

'access_token' => $user->createToken($device, expiresAt: $expiresAt)->plainTextToken,

I've not seen a colon used like this before within the function parameters, could you explain how/why you have done it this way?

avatar

The best explanation probably is my video here: PHP 8 Named Arguments: Practical Example

avatar

Thank you will check that out :)

avatar
You can use Markdown
avatar
Alexandre Junior da Costa

So, if the user sets remember as true, then the token is permanent until explicitly logged out?

Is that a normal/good practice?

I am building a mobile app using SAP's AppGyver and will need to build an API for it. I don't want the user having to login everytime he opens the app, and I was wondering if this is the right approach

I've seen people talinkg about using a refresh token, but did not quite get the logic for it.

avatar

Yes, the token is then permanent. At least, that's how I've always been using it, in my experience.

avatar
You can use Markdown
avatar

Still getting Errors The GET method is not supported for route api/v1/auth/login. Supported methods: POST. Postman 405 Method Not Allowed [http://project6.lcl/api/v1/auth/login]

avatar

From your questions, I noticed you are a beginner. I'd give you this advice. And I am very certain this will help you. As a beginner, you have to watch beginner videos first. I would advice to go pick up Beginner tutorials (start from scratch) on YouTube. Learn API. Learn Postman or even the ThunderClient on VS Code. Watch 1 or 2 beginner tutorial(s) on Laravel. Povilas has a video API course here on his platform; watch it. Then, come back to this.

Personally, I feel very bored watching videos. I achieve practically nothing. Text-based is the way for me now. I only watch a brief video to see the beginner intro on any very unfamiliar new technology I want to learn (some I have learned without videos). After that video or 2, any other video I watch without coding is practically wasting my precious time. I simply dive straight into coding, text-based tutorials and documentation.

Again, I sense frustration and anger in your tone. If you must succeed at programming as a beginner, you must do away with these two. Because as experienced as we are, we still get frustrated. What happens if a bug keeps your app progress at a halt for 2 weeks or perhaps, a month? I've been in that position when I was starting. One of these, I searched for the answer on Google and StackOverflow but couldn't find anything helpful because I didn't know what it was nor what to ask until I figured out the solution on my own and posted the answer on StackOverflow. And that was when I learned the skill to read and understand errors. Now, I must say, I debug very well that bugs never keep me hanging ever again. Do not get frustrated. It makes learning, harder for you.

Laravel, other frameworks and programming languages speak to you in their errors. Sometimes, they even go a step further to suggest to you how to resolve the error (debug the code). Read those errors line by line and understand what it says to be able to find the file or process it is pointing to, to debug it.

On a final note, programming is a step-by-step process. Every knowledge builds on top of the previous. Any basic fundamental step you miss on your journey, will come back to haunt you. And you will be forced to go back to the basics. Trust me, you have a lot to lose if you find yourself in this position. It will be long to list out all that could possibly go wrong. You don't want this, believe me.

avatar

And go to your Postman app/website and change the GET method to POST to solve this particular problem

avatar
You can use Markdown
avatar

When I put in the wrong credentials (email) I am not getting the error. I recieve the laravel main screen and 200 OK message.

avatar

do a git diff on your branch compared to the branch on github as if you entering the wrong credentials you shouldn't see an 200 error

avatar

I downloaded the code from github and it is doing the exact same thing. It appears that I have xsrf token and it is already authenticating me. How do I remove the token?

avatar

i dont have the repo to hand but you should have the logout route - try that

avatar
You can use Markdown
avatar
Ngozi Stephen Onyemauche

Plsease i a i have being followwing the tutorial, my login controller is not logging in with the bearer token is showing 500 status code. i have being trying to understand the problem, pls can someone help me out. it worked during registration and login but when i got to video 4 (get/ update user) it starts showing 500 status code

avatar
Ngozi Stephen Onyemauche

I have seen my mistake thank you

avatar
You can use Markdown
avatar

Why not using the Auth::attempt($request->validated())) in order to validate the password. I got an error when i used Hash::check($request->password, $user->password)) => 'This password does not use the Bcrypt algorithm.' and it seems logicaly because on register we didn't used the Hash::make() to provide the correct password.

avatar

This course was written on an older version of Laravel where Hash::check() was pretty common to use for password check. At the same time, Auth::attempt() does things a little bit different - it does not validate the password, but it tries to log the user in.

In other words, using Auth::attempt() will create a session for the user if his password is correct, while Hash::check() would just have returned true/false

avatar
You can use Markdown
avatar

I've got the following error:

"message": "Carbon\Carbon::rawAddUnit(): Argument #3 ($value) must be of type int|float, string given, called in D:\GithubRepositorios\ParkingAppApi\vendor\nesbot\carbon\src\Carbon\Traits\Units.php on line 356"

Solved by passing the session lifetime, which is a string, as an integer to addMinutes method from Carbon::now():

$expiresAt = $request->remember ? null : now()->addMinutes((int) config('session.lifetime'));

avatar
You can use Markdown
avatar
You can use Markdown