Back to Course |
Build Laravel API for Car Parking App: Step-By-Step

User Area: Get/Update Profile

As in every application, users should be able to update their profile. Personally, I like to separate two actions: change profile details and change password.

So, I vote for these API endpoints:

  • GET /profile - to view profile details
  • PUT /profile - to update name/email
  • PUT /password - to update the password

You could also make both PUT actions into one endpoint, with an if-else statement, but I personally like the separation of those concerns.


Get/Update Profile

Let's generate a Profile Controller - this time with two methods in it.

I will still keep the namespace of Auth because those features are related to the authenticated users.

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

This will be the code inside.

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

namespace App\Http\Controllers\Api\V1\Auth;
 
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Validation\Rule;
 
class ProfileController extends Controller
{
public function show(Request $request)
{
return response()->json($request->user()->only('name', 'email'));
}
 
public function update(Request $request)
{
$validatedData = $request->validate([
'name' => ['required', 'string'],
'email' => ['required', 'email', Rule::unique('users')->ignore(auth()->user())],
]);
 
auth()->user()->update($validatedData);
 
return response()->json($validatedData, Response::HTTP_ACCEPTED);
}
}

Not sure I need to explain much here: in the show() method we just show a few fields of a logged-in user (we don't show any ID or password-sensitive fields), and in the update() method we validate the data, update the DB row and return the updated data as JSON.

Now, the most important part: how do we get that auth()->user() or $request->user() automatically?

In the routes, we will make those endpoints as a group, with the Middleware auth:sanctum. Then, we pass a Bearer token in the API request. Yes, the one that we got returned from login/register.

routes/api.php:

Route::middleware('auth:sanctum')->group(function () {
Route::get('profile', [Auth\ProfileController::class, 'show']);
Route::put('profile', [Auth\ProfileController::class, 'update']);
});

Now, if we try to make a request without any token, we should get a 401 status code, which means unauthenticated.

Laravel API Profile

But look what happens if we make the same request, but add a "Bearer Token" in the Auth section of Postman: it returns the user's fields!

Laravel API Profile

Notice: in your API client the Bearer token may be placed elsewhere than in my Postman, check for your tool's documentation.

Now, what happens if we try to update the name/email? The same Bearer token should be included, too, for this and all other upcoming logged-in requests.

Laravel API Profile

Successfully updated!

Now, let's create the Change Password endpoint.


Change Password

By now, you could totally do this one without my help, right? It will be almost identical. But let me just list my actions, with just a few comments:

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

This will be an invokable Controller:

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

namespace App\Http\Controllers\Api\V1\Auth;
 
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules\Password;
 
class PasswordUpdateController extends Controller
{
public function __invoke(Request $request)
{
$request->validate([
'current_password' => ['required', 'current_password'],
'password' => ['required', 'confirmed', Password::defaults()],
]);
 
auth()->user()->update([
'password' => Hash::make($request->input('password')),
]);
 
return response()->json([
'message' => 'Your password has been updated.',
], Response::HTTP_ACCEPTED);
}
}

Now, we add it to the routes.

routes/api.php:

Route::middleware('auth:sanctum')->group(function () {
Route::get('profile', [Auth\ProfileController::class, 'show']);
Route::put('profile', [Auth\ProfileController::class, 'update']);
Route::put('password', Auth\PasswordUpdateController::class);
});

Try it out... Success!

Laravel API Profile


Logout

Now we know how to make the requests for the logged-in user, passing a Bearer Token.

If we want the user to log out of the API access, all we need to do is destroy the token that Sanctum had generated at the login/register.

So, a new Controller:

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

And a new endpoint inside the same group with auth:sanctum Middleware:

routes/api.php:

Route::post('auth/logout', Auth\LogoutController::class);

The content of the method is very simple:

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

namespace App\Http\Controllers\Api\V1\Auth;
 
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
 
class LogoutController extends Controller
{
public function __invoke(Request $request)
{
$request->user()->currentAccessToken()->delete();
 
return response()->noContent();
}
}

We can access the currently logged-in user with $request->user() or auth()->user(), they are identical. And then, we call the Sanctum's methods of currentAccessToken() and then delete(), returning the noContent() which shows 204 HTTP Status Code.

After this call, the previous token will be deleted and no longer valid for any future requests, the user would need to re-login again to get a new token.