<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: ashrakt</title>
    <description>The latest articles on Forem by ashrakt (@ashrakt_amin).</description>
    <link>https://forem.com/ashrakt_amin</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1278973%2F2b171f73-07a9-459f-a060-2822490e2f31.jpg</url>
      <title>Forem: ashrakt</title>
      <link>https://forem.com/ashrakt_amin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ashrakt_amin"/>
    <language>en</language>
    <item>
      <title>Building API Authentication System with Laravel 12 &amp; Sanctum: Register, Login, OTP &amp; Password Reset</title>
      <dc:creator>ashrakt</dc:creator>
      <pubDate>Tue, 04 Nov 2025 15:02:41 +0000</pubDate>
      <link>https://forem.com/ashrakt_amin/complete-api-authentication-with-laravel-12-sanctum-56l3</link>
      <guid>https://forem.com/ashrakt_amin/complete-api-authentication-with-laravel-12-sanctum-56l3</guid>
      <description>&lt;p&gt;Laravel Sanctum provides an authentication system for SPAs (single page applications), mobile applications, and simple, token based APIs. Sanctum allows each user of your application to generate multiple API tokens for their account. These tokens may be granted abilities / scopes which specify which actions the tokens are allowed to perform.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;folders&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;App-&amp;gt;[
     Http-&amp;gt;[
           Controllers\Api\Auth-&amp;gt;[
                                AuthController,
                                OTPController,
                                PasswordResetController
         ],Requests\Auth-&amp;gt;[
                         LoginUserRequest,
                         RegisterUserRequest,
                         ResetPasswordRequest,
                         SendOTPRequest,
                         VerifyOTPRequest
        ],Resources-&amp;gt;[
                      SuccessResource,
                      ErrorResource,
                      User-&amp;gt;[
                            AuthResource,
                            UserResource]
    ],Jobs-&amp;gt;[SendMailJob],
      Mail-&amp;gt;[OTPMail],
      Services-&amp;gt;[OTPService]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;1: Install Laravel 12 and Sanctum&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create new Laravel 12 project
laravel new sanctum-auth
cd sanctum-auth

# Install Sanctum
php artisan install:api

# Run migrations (creates personal_access_tokens table)
php artisan migrate

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;2: Configure Sanctum&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;config/sanctum.php&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  'stateful' =&amp;gt; explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
        '%s%s',
        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
        Sanctum::currentApplicationUrlWithPort(),
    ))),
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Stateful domains tell Sanctum which domains can use cookies and sessions for authentication, allowing the frontend to communicate with the API seamlessly!
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;.env&lt;/em&gt;&lt;br&gt;
SANCTUM_STATEFUL_DOMAINS=localhost,127.0.0.1,127.0.0.1:3000&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;3: Update User Model&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app/Models/User.php
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;


class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    protected $fillable = [
        'name',
        'email',
        'password',
        'phone',
        'email_verified_at',
        'otp',
        'otp_expires_at',
        'otp_verified_at'
    ];

    protected $hidden = [
        'password',
        'remember_token',
        'otp'

    ];


    protected function casts(): array
    {
        return [
            'email_verified_at' =&amp;gt; 'datetime',
            'password' =&amp;gt; 'hashed',
            'otp_expires_at' =&amp;gt; 'datetime',
            'otp_verified_at' =&amp;gt; 'datetime',
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;&lt;strong&gt;4: Create Auth Controller, Register And Login Request, Auth And User Resource&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Auth Controller&lt;/em&gt;&lt;br&gt;
&lt;code&gt;php artisan make:controller Api/Auth/AuthController&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app/Http/Controllers/AuthController.php
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Controllers\Api\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginUserRequest;
use App\Http\Requests\Auth\RegisterUserRequest;
use App\Http\Resources\User\AuthResource;
use App\Http\Resources\ErrorResource;
use App\Http\Resources\SuccessResource;
use App\Http\Resources\User\UserResource;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class AuthController extends Controller
{
    public function register(RegisterUserRequest $request)
    {
        $validated = $request-&amp;gt;validated();

        $user = User::create([
            'name' =&amp;gt; $validated['name'],
            'email' =&amp;gt; $validated['email'],
            'password' =&amp;gt; Hash::make($validated['password']),
            'phone' =&amp;gt; $validated['phone'],
        ]);

        $token = $user-&amp;gt;createToken('auth_token')-&amp;gt;plainTextToken;

        $authData = [
            'user' =&amp;gt; $user,
            'token' =&amp;gt; $token,
            'token_type' =&amp;gt; 'Bearer'
        ];

        return new AuthResource($authData);
    }

    public function login(LoginUserRequest $request)
    {
        $validated = $request-&amp;gt;validated();

        $user = User::where('email', $validated['email'])-&amp;gt;first();

        if (!$user || !Hash::check($validated['password'], $user-&amp;gt;password)) {
            return new ErrorResource([
                'message' =&amp;gt; 'Invalid credentials',
                'status_code' =&amp;gt; 401
            ]);
        }

        $token = $user-&amp;gt;createToken('auth_token')-&amp;gt;plainTextToken;

        $authData = [
            'user' =&amp;gt; $user,
            'token' =&amp;gt; $token,
            'token_type' =&amp;gt; 'Bearer'
        ];

        return new AuthResource($authData);
    }

    public function logout(Request $request)
    {
        $request-&amp;gt;user()-&amp;gt;currentAccessToken()-&amp;gt;delete();

        return new SuccessResource([
            'message' =&amp;gt; 'Logged out successfully'
        ]);
    }


//The user() function retrieves the authenticated user's profile data using their Bearer token.

    public function user(Request $request)
    {
        return new SuccessResource([
            'message' =&amp;gt; 'User data retrieved successfully',
            'data' =&amp;gt; new UserResource($request-&amp;gt;user())
        ]);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$token = $user-&amp;gt;createToken('auth_token');
        return $token;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;the json respone &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcpm35u1wthq5dw0d7na.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcpm35u1wthq5dw0d7na.PNG" alt=" " width="800" height="340"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;em&gt;Create RegisterUserRequest class&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:request Auth/RegisterUserRequest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;-app/Http/Requests/Auth/RegisterUserRequest.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

class RegisterUserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true; // Set to true to allow all users
    }

    /**
     * Get the validation rules that apply to the request.
     */
    public function rules(): array
    {
        return [
            'name' =&amp;gt; 'required|string|max:255',
            'email' =&amp;gt; 'required|string|email|max:255|unique:users',
            'password' =&amp;gt; 'required|string|min:8|confirmed',
            'phone' =&amp;gt; 'required|string|max:20'
        ];
    }

    /**
     * Get custom messages for validator errors.
     *
     * @return array&amp;lt;string, string&amp;gt;
     */
    public function messages(): array
    {
        return [
            'name.required' =&amp;gt; 'The name field is required.',
            'name.string' =&amp;gt; 'The name must be a string.',
            'name.max' =&amp;gt; 'The name may not be greater than 255 characters.',

            'email.required' =&amp;gt; 'The email field is required.',
            'email.email' =&amp;gt; 'Please enter a valid email address.',
            'email.unique' =&amp;gt; 'This email is already registered.',

            'password.required' =&amp;gt; 'The password field is required.',
            'password.min' =&amp;gt; 'The password must be at least 8 characters.',
            'password.confirmed' =&amp;gt; 'Password confirmation does not match.',

            'phone.required' =&amp;gt; 'The phone field is required.',
            'phone.string' =&amp;gt; 'The phone must be a string.',
            'phone.max' =&amp;gt; 'The phone may not be greater than 20 characters.',
        ];
    }



    protected function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(
            response()-&amp;gt;json([
                'status' =&amp;gt; 'error',
                'message' =&amp;gt; 'Validation failed',
                'errors' =&amp;gt; $validator-&amp;gt;errors()
            ], 422)
        );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Login Request&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;-&lt;code&gt;php artisan make:request Auth/LoginUserRequest&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Requests\Auth;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;


class LoginUserRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'email' =&amp;gt; 'required|email',
            'password' =&amp;gt; 'required'
        ];
    }

    public function messages(): array
    {
        return [
            'email.required' =&amp;gt; 'The email field is required.',
            'email.email' =&amp;gt; 'Please enter a valid email address.',
            'password.required' =&amp;gt; 'The password field is required.',
        ];
    }


    protected function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(
            response()-&amp;gt;json([
                'status' =&amp;gt; 'error',
                'message' =&amp;gt; 'Validation failed',
                'errors' =&amp;gt; $validator-&amp;gt;errors()
            ], 422)
        );
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Auth Resource&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:resource User/AuthResource&lt;/code&gt;&lt;br&gt;
app/Http/Resources/User/AuthResource.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Resources\User;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class AuthResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'user' =&amp;gt; new UserResource($this['user']),
            'access_token' =&amp;gt; $this['token'],
            'token_type' =&amp;gt; $this['token_type'] ?? 'Bearer',
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;User Resource&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:resource USer/UserResource&lt;/code&gt;&lt;br&gt;
app/Http/Resources/User/UserResource.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Resources\User;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' =&amp;gt; $this-&amp;gt;id,
            'name' =&amp;gt; $this-&amp;gt;name,
            'email' =&amp;gt; $this-&amp;gt;email,
            'phone' =&amp;gt; $this-&amp;gt;phone,
            'email_verified_at' =&amp;gt; $this-&amp;gt;email_verified_at?-&amp;gt;toDateTimeString(),
            'created_at' =&amp;gt; $this-&amp;gt;created_at?-&amp;gt;toDateTimeString(),
            'updated_at' =&amp;gt; $this-&amp;gt;updated_at?-&amp;gt;toDateTimeString(),
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Success Resource&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:resource SuccessResource&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app/Http/Resources/SuccessResource.php
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class SuccessResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'status' =&amp;gt; 'success',
            'message' =&amp;gt; $this['message'],
            'data' =&amp;gt; $this['data'] ?? null,
        ];
    }

    public function withResponse($request, $response)
    {
        $response-&amp;gt;setStatusCode($this['status_code'] ?? 200);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Error Resource&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:resource ErrorResource&lt;/code&gt;&lt;br&gt;
-app/Http/Resources/ErrorResource.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class ErrorResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'status' =&amp;gt; 'error',
            'message' =&amp;gt; $this['message'],
            'errors' =&amp;gt; $this['errors'] ?? null,
        ];
    }

    public function withResponse($request, $response)
    {
        $response-&amp;gt;setStatusCode($this['status_code'] ?? 400);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;*&lt;em&gt;Create OTP Controller, OTP Requests *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;OTP Controller&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This OTPController class is a One-Time Password (OTP) authentication controller for a Laravel application. Here's what it does:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Main Purpose&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;1- Email verification during registration&lt;br&gt;
2- Two-factor authentication (2FA)&lt;br&gt;
3- Password reset verification&lt;br&gt;
4- Account recovery&lt;/p&gt;

&lt;p&gt;-php artisan make:controller Api/Auth/OTPController&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Controllers\Api\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\SendOTPRequest;
use App\Http\Requests\Auth\VerifyOTPRequest;
use App\Http\Resources\ErrorResource;
use App\Http\Resources\SuccessResource;
use App\Jobs\SendMailJob;
use App\Models\User;
use App\Services\OTPService;

class OTPController extends Controller
{

    protected $otpService;

    public function __construct(OTPService $otpService)
    {
        $this-&amp;gt;otpService = $otpService;
    }

    public function sendOTP(SendOTPRequest $request)
    {
        $validated = $request-&amp;gt;validated();

        $user = User::where('email', $validated['email'])-&amp;gt;first();

        // Generate OTP using service
        $otpData = $this-&amp;gt;otpService-&amp;gt;generateOTP();

        try {
            // Send OTP via Email
            SendMailJob::dispatch(
                $user-&amp;gt;name,
                $user-&amp;gt;email,
                $otpData['otp']
            );


            // Update user with OTP data
            $user-&amp;gt;update([
                'otp' =&amp;gt; $otpData['otp'],
                'otp_expires_at' =&amp;gt; $otpData['otp_expires_at']
            ]);


            return new SuccessResource([
                'message' =&amp;gt; 'OTP sent successfully to your email',
                'data' =&amp;gt; [
                    'expires_in' =&amp;gt; 10,
                    'email' =&amp;gt; $user-&amp;gt;email
                ]
            ]);
        } catch (\Exception $e) {
            return new ErrorResource([
                'message' =&amp;gt; 'Failed to send OTP. Please try again.',
                'error_code' =&amp;gt; 'EMAIL_SEND_FAILED',
                'status_code' =&amp;gt; 500
            ]);
        }
    }


    public function verifyOTP(VerifyOTPRequest $request)
    {
        $validated = $request-&amp;gt;validated();

         // Use email verification method for OTP verification
        $user = $this-&amp;gt;otpService-&amp;gt;verifyOTPAndVerifyEmail(
              $validated['email'], 
              $validated['otp']
          );

        if (!$user) {
            return new ErrorResource([
                'message' =&amp;gt; 'Invalid or expired OTP',
                'status_code' =&amp;gt; 400
            ]);
        }

        // Clear OTP and mark email as verified
        $this-&amp;gt;otpService-&amp;gt;clearOTP($user);

        return new SuccessResource([
            'message' =&amp;gt; 'OTP verified successfully'
        ]);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;OTP Requests&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:request Auth/SendOTPRequest&lt;/code&gt;&lt;br&gt;
&lt;code&gt;php artisan make:request Auth/VerifyOTPRequest&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;-app/Http/Requests/Auth/SendOTPRequest.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Requests\Auth;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;


class SendOTPRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'email' =&amp;gt; 'required|email|exists:users,email'
        ];
    }


      public function messages(): array
    {
        return [
            'email.required' =&amp;gt; 'The email field is required.',
            'email.email' =&amp;gt; 'Please enter a valid email address.',
            'email.exists' =&amp;gt; 'No account found with this email address.',
        ];
    }


    protected function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(
            response()-&amp;gt;json([
                'status' =&amp;gt; 'error',
                'message' =&amp;gt; 'Validation failed',
                'errors' =&amp;gt; $validator-&amp;gt;errors()
            ], 422)
        );
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;-app/Http/Requests/Auth/VerifyOTPRequest.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Requests\Auth;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;

class VerifyOTPRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'email' =&amp;gt; 'required|email|exists:users,email',
            'otp' =&amp;gt; 'required|digits:6'
        ];
    }


    public function messages(): array
    {
        return [
            // Email field messages
            'email.required' =&amp;gt; 'Email address is required.',
            'email.email' =&amp;gt; 'Please provide a valid email address.',
            'email.exists' =&amp;gt; 'This email address is not registered in our system.',

            // OTP field messages
            'otp.required' =&amp;gt; 'OTP code is required.',
            'otp.digits' =&amp;gt; 'OTP code must be exactly 6 digits.',
        ];
    }


    protected function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(
            response()-&amp;gt;json([
                'status' =&amp;gt; 'error',
                'message' =&amp;gt; 'Validation failed',
                'errors' =&amp;gt; $validator-&amp;gt;errors()
            ], 422)
        );
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;OTP Service&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The OTP Service prevents duplication in code and prepares for future changes, Even though the logic is simple now, having it in one place means:

&lt;ul&gt;
&lt;li&gt;One change affects all OTP usage&lt;/li&gt;
&lt;li&gt;Easy to test and maintain&lt;/li&gt;
&lt;li&gt;Ready for evolution when requirements change&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;php artisan make:class Services/OTPService&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Services;

use App\Models\User;
use Illuminate\Support\Carbon;

class OTPService
{
    public function generateOTP(): array
    {
        return [
            'otp' =&amp;gt; rand(100000, 999999),
            'otp_expires_at' =&amp;gt; Carbon::now()-&amp;gt;addMinutes(10)
        ];
    }

    public function verifyOTP(string $email, string $otp): ?User
    {
        return User::where('email', $email)
            -&amp;gt;where('otp', $otp)
            -&amp;gt;where('otp_expires_at', '&amp;gt;', Carbon::now())
            -&amp;gt;first();
    }

    public function verifyOTPAndVerifyEmail(string $email, string $otp): ?User
    {
        $user = $this-&amp;gt;verifyOTP($email, $otp);

        if ($user) {
            $user-&amp;gt;update([
                'otp' =&amp;gt; null,
                'otp_expires_at' =&amp;gt; null,
                'email_verified_at' =&amp;gt; Carbon::now()
            ]);
        }

        return $user;
    }

    public function clearOTP(User $user): void
    {
        $user-&amp;gt;update([
            'otp' =&amp;gt; null,
            'otp_expires_at' =&amp;gt; null,
        ]);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Queue for Sending Email With Database Driver&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Benefits:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;-Improved Application Performance -&amp;gt; User doesn't wait for email to send&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic Retries -&amp;gt; If sending fails, it retries automatically&lt;/li&gt;
&lt;li&gt;Error Handling -&amp;gt; Failed jobs are logged and can be retried&lt;/li&gt;
&lt;li&gt;Data Safety -&amp;gt; Jobs are stored even if server restarts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Complete Setup&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;i: Environment Setup&lt;br&gt;
&lt;em&gt;.env&lt;/em&gt;&lt;br&gt;
&lt;code&gt;QUEUE_CONNECTION=database&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ii: create queue tables if they don't exist:&lt;/p&gt;

&lt;p&gt;php artisan queue:table&lt;br&gt;
php artisan queue:failed-table&lt;br&gt;
php artisan migrate&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:job SendMailJob&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Jobs;

use App\Mail\OTPMail;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;

class SendMailJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $name;
    protected $email;
    protected $otp;


    public function __construct($name, $email, $otp)
    {
        $this-&amp;gt;name = $name;
        $this-&amp;gt;email = $email;
        $this-&amp;gt;otp = $otp;
    }



    public function handle(): void
    {
        Mail::to($this-&amp;gt;email)-&amp;gt;send(new OTPMail(
            otp: $this-&amp;gt;otp,
            userName: $this-&amp;gt;name,
            expiresIn: 10,
            purpose: 'verification'
        ));
    }

    public function failed(\Throwable $exception): void
    {
        Log::error('SendMailJob failed: ' . $exception-&amp;gt;getMessage());
        Log::error('Exception details: ', [
            'file' =&amp;gt; $exception-&amp;gt;getFile(),
            'line' =&amp;gt; $exception-&amp;gt;getLine(),
            'trace' =&amp;gt; $exception-&amp;gt;getTraceAsString()
        ]);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Running the Queue Worker&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan queue:work&lt;/code&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Complete SendGrid Setup Guide&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;1: Create SendGrid Account&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go to &lt;a href="//SendGrid.com"&gt;SendGrid.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sign up for a free account (100 emails/day)&lt;/li&gt;
&lt;li&gt;Verify your email address&lt;/li&gt;
&lt;li&gt;Complete account setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2: Get SendGrid API Key&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Login to SendGrid dashboard&lt;/li&gt;
&lt;li&gt;Go to Settings → API Keys&lt;/li&gt;
&lt;li&gt;Click Create API Key&lt;/li&gt;
&lt;li&gt;Give it a name (e.g., "Laravel App")&lt;/li&gt;
&lt;li&gt;Choose Full Access or Restricted Access&lt;/li&gt;
&lt;li&gt;Copy the API key (you won't see it again!)&lt;/li&gt;
&lt;li&gt;.env file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAIL_MAILER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=your_sendgrid_api_key_here
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=from@example.com
MAIL_FROM_NAME="Your App"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;4: Sender Authentication&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Option A: Single Sender Verification (Quick Start)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;1- Go to Settings → Sender Authentication&lt;br&gt;
2- Click Verify a Single Sender&lt;br&gt;
3-Fill in the form:&lt;br&gt;
 From Email: &lt;a href="mailto:your-email@example.com"&gt;your-email@example.com&lt;/a&gt;&lt;br&gt;
 From Name: Your Name&lt;br&gt;
 Reply To: &lt;a href="mailto:your-email@example.com"&gt;your-email@example.com&lt;/a&gt;&lt;br&gt;
 Address: Your physical address (required by law)&lt;br&gt;
 Click Create&lt;br&gt;
4-Check your email and click verification link&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Option B: Domain Authentication (Recommended for Production)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;1- Go to Settings → Sender Authentication&lt;br&gt;
2- Click Authenticate Your Domain&lt;br&gt;
3- Enter your domain (e.g., example.com)&lt;br&gt;
4- Choose Default Link Branding&lt;br&gt;
5- SendGrid provides DNS records - add these to your domain's DNS&lt;br&gt;
6- Wait for verification (can take 24-48 hours)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5: Create Mail Class in Laravel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;php artisan make:mail OTPMail&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;

class OTPMail extends Mailable
{
    use Queueable, SerializesModels;

    public $otp;
    public $userName;
    public $expiresIn;
    public $purpose;

    public function __construct($otp, $userName = null, $expiresIn = 10, $purpose = 'verification')
    {
        $this-&amp;gt;otp = $otp;
        $this-&amp;gt;userName = $userName;
        $this-&amp;gt;expiresIn = $expiresIn;
        $this-&amp;gt;purpose = $purpose;
    }



    public function content(): Content
    {
        return new Content(
            view: 'emails.otp',
        );
    }

    public function attachments(): array
    {
        return [];
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;Create Email Template&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;

&amp;lt;head&amp;gt;
    &amp;lt;meta charset="utf-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1"&amp;gt;
    &amp;lt;title&amp;gt;OTP Verification - {{ config('app.name') }}&amp;lt;/title&amp;gt;
    &amp;lt;style&amp;gt;
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            color: #333;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 500px;
            margin: 0 auto;
        }

        .email-wrapper {
            background: white;
            border-radius: 15px;
            overflow: hidden;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
        }

        .content {
            padding: 40px 30px;
        }

        .greeting {
            font-size: 18px;
            margin-bottom: 25px;
            color: #4B5563;
        }

        .otp-container {
            text-align: center;
            margin: 30px 0;
        }

        .otp-label {
            font-size: 16px;
            color: #6B7280;
            margin-bottom: 15px;
        }

        .otp-code {
            font-size: 48px;
            font-weight: bold;
            color: #4F46E5;
            letter-spacing: 8px;
            font-family: 'Courier New', monospace;
            background: #F8FAFC;
            padding: 20px;
            border-radius: 10px;
            border: 2px dashed #E5E7EB;
            margin: 15px 0;
        }

        .info-box {
            background: #F0F9FF;
            border: 1px solid #BAE6FD;
            border-radius: 10px;
            padding: 20px;
            margin: 25px 0;
        }

        .info-item {
            display: flex;
            align-items: center;
            margin-bottom: 10px;
        }

        .info-item:last-child {
            margin-bottom: 0;
        }

        .info-icon {
            font-size: 18px;
            margin-right: 12px;
        }

        .footer {
            text-align: center;
            padding: 30px;
            background: #F8FAFC;
            border-top: 1px solid #E5E7EB;
        }

        .footer p {
            color: #6B7280;
            font-size: 14px;
            margin-bottom: 5px;
        }

        .app-name {
            color: #4F46E5;
            font-weight: 600;
        }

        @media (max-width: 600px) {
            .content {
                padding: 30px 20px;
            }

            .otp-code {
                font-size: 36px;
                letter-spacing: 6px;
                padding: 15px;
            }

        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
    &amp;lt;div class="container"&amp;gt;
        &amp;lt;div class="email-wrapper"&amp;gt;
            &amp;lt;div class="content"&amp;gt;
                &amp;lt;div class="greeting"&amp;gt;
                    @if ($userName)
                        Hello &amp;lt;strong&amp;gt;{{ $userName }}&amp;lt;/strong&amp;gt;,
                    @else
                        Hello,
                    @endif
                &amp;lt;/div&amp;gt;

                &amp;lt;p&amp;gt;You're just one step away! Use the following verification code to complete your request:&amp;lt;/p&amp;gt;

                &amp;lt;div class="otp-container"&amp;gt;
                    &amp;lt;div class="otp-label"&amp;gt;Your verification code:&amp;lt;/div&amp;gt;
                    &amp;lt;div class="otp-code"&amp;gt;{{ $otp }}&amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;

                &amp;lt;div class="info-box"&amp;gt;
                    &amp;lt;div class="info-item"&amp;gt;
                        &amp;lt;span class="info-icon"&amp;gt;⏰&amp;lt;/span&amp;gt;
                        &amp;lt;span&amp;gt;&amp;lt;strong&amp;gt;Expires in:&amp;lt;/strong&amp;gt; {{ $expiresIn }} minutes&amp;lt;/span&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div class="info-item"&amp;gt;
                        &amp;lt;span class="info-icon"&amp;gt;🚀&amp;lt;/span&amp;gt;
                        &amp;lt;span&amp;gt;&amp;lt;strong&amp;gt;Purpose:&amp;lt;/strong&amp;gt;
                            @if ($purpose === 'verification')
                                Account Verification
                            @elseif($purpose === 'password_reset')
                                Password Reset
                            @elseif($purpose === 'login')
                                Login Verification
                            @else
                                Security Verification
                            @endif
                        &amp;lt;/span&amp;gt;
                    &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;

            &amp;lt;div class="footer"&amp;gt;
                &amp;lt;p&amp;gt;&amp;amp;copy; {{ date('Y') }} &amp;lt;span class="app-name"&amp;gt;{{ config('app.name') }}&amp;lt;/span&amp;gt;. All rights
                    reserved.&amp;lt;/p&amp;gt;
                &amp;lt;p&amp;gt;This email was sent via Secure OTP System&amp;lt;/p&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Password Reset Controller, Send OTP And Reset password Request&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:controller Api/Auth/PasswordResetController&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app/Http/Controllers/Api/Auth/PasswordResetController.php
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Controllers\Api\Auth;

use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\ResetPasswordRequest;
use App\Http\Requests\Auth\SendOTPRequest;
use App\Http\Resources\ErrorResource;
use App\Http\Resources\SuccessResource;
use App\Jobs\SendMailJob;
use App\Models\User;
use App\Services\OTPService;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Hash;

class PasswordResetController extends Controller
{

    protected $otpService;

    public function __construct(OTPService $otpService)
    {
        $this-&amp;gt;otpService = $otpService;
    }


    public function forgotPassword(SendOTPRequest $request)
    {
        $validated = $request-&amp;gt;validated();

        $user = User::where('email', $validated['email'])-&amp;gt;first();

        // Generate OTP using service
        $otpData = $this-&amp;gt;otpService-&amp;gt;generateOTP();

        try {
            // Send OTP via Email
            SendMailJob::dispatch(
                $user-&amp;gt;name,
                $user-&amp;gt;email,
                $otpData['otp']
            );

            $user-&amp;gt;update([
                'otp' =&amp;gt; $otpData['otp'],
                'otp_expires_at' =&amp;gt; $otpData['otp_expires_at']
            ]);

            return new SuccessResource([
                'message' =&amp;gt; 'OTP sent successfully to your email',
                'data' =&amp;gt; [
                    'expires_in' =&amp;gt; 10,
                    'email' =&amp;gt; $user-&amp;gt;email
                ]
            ]);
        } catch (\Exception $e) {
            return new ErrorResource([
                'message' =&amp;gt; 'Failed to send OTP. Please try again.',
                'error_code' =&amp;gt; 'EMAIL_SEND_FAILED',
                'status_code' =&amp;gt; 500
            ]);
        }
    }

    public function resetPassword(ResetPasswordRequest $request)
    {
        $validated = $request-&amp;gt;validated();

  // Use basic OTP verification for password reset (no email verification)
        $user = $this-&amp;gt;otpService-&amp;gt;verifyOTP(
            $validated['email'],
            $validated['otp']
        );


        if (!$user) {
            return new ErrorResource([
                'message' =&amp;gt; 'Invalid or expired OTP',
                'status_code' =&amp;gt; 400
            ]);
        }

        // Clear OTP and mark email as verified
        $this-&amp;gt;otpService-&amp;gt;clearOTP($user);

        $user-&amp;gt;tokens()-&amp;gt;delete();

        return new SuccessResource([
            'message' =&amp;gt; 'Password reset successfully'
        ]);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why $user-&amp;gt;tokens()-&amp;gt;delete();?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Security measure during password reset to:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Invalidate all active sessions&lt;/li&gt;
&lt;li&gt;Force re-login with new password&lt;/li&gt;
&lt;li&gt;Prevent token reuse if account was compromised&lt;/li&gt;
&lt;li&gt;Log out all devices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Result:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User must login again on all devices&lt;/li&gt;
&lt;li&gt;Old tokens become useless&lt;/li&gt;
&lt;li&gt;Fresh start with new password&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Reset Password Request&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
namespace App\Http\Requests\Auth;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Contracts\Validation\Validator;
use Illuminate\Http\Exceptions\HttpResponseException;


class ResetPasswordRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }


    public function rules(): array
    {
        return [
            'email'    =&amp;gt; 'required|email|exists:users,email',
            'otp'      =&amp;gt; 'required|digits:6',
            'password' =&amp;gt; 'required|string|min:8|confirmed',
        ];
    }


    public function messages(): array
    {
        return [
            'email.required' =&amp;gt; 'The email field is required.',
            'email.email' =&amp;gt; 'Please enter a valid email address.',
            'email.exists' =&amp;gt; 'No account found with this email address.',

            'password.required' =&amp;gt; 'The password field is required.',
            'password.min' =&amp;gt; 'The password must be at least 8 characters.',
            'password.confirmed' =&amp;gt; 'Password confirmation does not match.',

            'otp.required' =&amp;gt; 'OTP code is required.',
            'otp.digits' =&amp;gt; 'OTP code must be exactly 6 digits.',
        ];
    }


    protected function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(
            response()-&amp;gt;json([
                'status' =&amp;gt; 'error',
                'message' =&amp;gt; 'Validation failed',
                'errors' =&amp;gt; $validator-&amp;gt;errors()
            ], 422)
        );
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Create API Routes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;routes/api.php
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Include Authentication Routes
require __DIR__ . '/auth.php';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;routes/auth.php
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

use App\Http\Controllers\Api\Auth\AuthController;
use App\Http\Controllers\Api\Auth\OTPController;
use App\Http\Controllers\Api\Auth\PasswordResetController;
use Illuminate\Support\Facades\Route;



// Public routes
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);

// OTP routes
Route::post('/send-otp', [OTPController::class, 'sendOTP']);
Route::post('/verify-otp', [OTPController::class, 'verifyOTP']);

// Password reset routes
Route::post('/forgot-password', [PasswordResetController::class, 'forgotPassword']);
Route::post('/reset-password', [PasswordResetController::class, 'resetPassword']);

//Protected routes
Route::middleware('auth:sanctum')-&amp;gt;group(function () {
    Route::delete('/logout', [AuthController::class, 'logout']);
    Route::get('/user', [AuthController::class, 'user']);
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;API Authentication System Implementation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Postman Automation Script&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fum4x9t9zv6w4ikx5f69w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fum4x9t9zv6w4ikx5f69w.png" alt=" " width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Postman Environment Variables&lt;/em&gt;&lt;br&gt;
-Two key variables configured:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fao9mlsnaywh1pa5hu8br.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fao9mlsnaywh1pa5hu8br.png" alt=" " width="800" height="243"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;url: Base API endpoint for all requests&lt;/li&gt;
&lt;li&gt;access-token: Authentication token automatically saved after login/register&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;register&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0c7kzqak1pmfmsueekwe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0c7kzqak1pmfmsueekwe.png" alt=" " width="800" height="529"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;login&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4iuresd5w6nmr8t12jg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb4iuresd5w6nmr8t12jg.png" alt=" " width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;logout&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flydf51wxycw0oy2qwp5d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flydf51wxycw0oy2qwp5d.png" alt=" " width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;OTP&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;send OTP&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm9xldqvl0n6bhp8yv97.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdm9xldqvl0n6bhp8yv97.png" alt=" " width="800" height="428"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc1n15113q1ca2j37mb5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foc1n15113q1ca2j37mb5.jpg" alt=" " width="800" height="1431"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;verify OTP&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuszi3f4tx0fwo8suk6jl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuszi3f4tx0fwo8suk6jl.png" alt=" " width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;password&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;forgot password&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdarul1ycytsa52tr899.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdarul1ycytsa52tr899.png" alt=" " width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;reset password&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feu5aavviquyuc42w01y0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feu5aavviquyuc42w01y0.png" alt=" " width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;authenticated user&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fha0hmamkbmwatuhkzllq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fha0hmamkbmwatuhkzllq.png" alt=" " width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>security</category>
      <category>laravel</category>
      <category>php</category>
    </item>
    <item>
      <title>Laravel HTTP Sessions</title>
      <dc:creator>ashrakt</dc:creator>
      <pubDate>Tue, 28 Oct 2025 16:00:38 +0000</pubDate>
      <link>https://forem.com/ashrakt_amin/laravel-http-sessions-pee</link>
      <guid>https://forem.com/ashrakt_amin/laravel-http-sessions-pee</guid>
      <description>&lt;p&gt;&lt;strong&gt;1. What are Sessions?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sessions are a core mechanism in web applications that allow a server to remember a user and maintain information about them across multiple visits or requests.&lt;/p&gt;

&lt;p&gt;Since the fundamental nature of the HTTP protocol is stateless (meaning the server forgets everything between one request and the next), sessions are crucial for providing a continuous, personalized, and functional user experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ex:&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Login Status&lt;/em&gt;&lt;br&gt;
Remembering that a user is signed in without requiring them to re-enter credentials on every page.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Shopping Cart Items&lt;/em&gt;&lt;br&gt;
Persisting the list of products a user has added to their cart, even as they navigate through the website. (This is crucial for Guest Users, where cart contents are temporarily stored in the session rather than the database).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Interface Preferences (Locale/Language)&lt;/em&gt;&lt;br&gt;
Recalling the user's chosen language (e.g., English/Arabic) to ensure consistent content display across the entire application."&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;2. How Sessions Work&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1- When you visit a site, Laravel creates a unique Session ID&lt;br&gt;
2- This ID is stored in a cookie (small file in your browser) called laravel_session&lt;br&gt;
3- Your actual data (username, cart items) is stored on the server, linked to your Session ID&lt;br&gt;
4- Every time you click a new page, your browser sends the cookie back so the server remembers you&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;3. Where Session Data is Stored(Session Drivers)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Session Driver is where the session data is stored on the server side (configured in config/session.php).&lt;/p&gt;

&lt;p&gt;1- Files (default): stored in storage/framework/sessions.&lt;br&gt;
2- Database: stored in a database table.&lt;br&gt;
3- Redis/Memcached: fast memory storage.&lt;br&gt;
4- Cookies: stored in secure, encrypted cookies.&lt;br&gt;
5- array: stored in a PHP array and will not be persisted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxc7i1w9hkq5lftq1zia3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxc7i1w9hkq5lftq1zia3.png" alt=" " width="695" height="296"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;4. Key Session Methods&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu6117h04bzc4qjn8y6n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyu6117h04bzc4qjn8y6n.png" alt=" " width="706" height="319"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;5. Session Security&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSRF Protection&lt;/li&gt;
&lt;li&gt;Encryption&lt;/li&gt;
&lt;li&gt;Session Regeneration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CSRF Protection(Cross-Site Request Forgery)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What it is&lt;/em&gt;&lt;br&gt;
What it prevents: Bad websites tricking you into doing actions on other sites where you're logged in (like changing their email or buying an item).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How Laravel Protects You&lt;/em&gt;&lt;br&gt;
Laravel uses a CSRF Token to ensure that any request trying to modify data (POST, PUT, DELETE, etc.) actually came from your application, not an external source.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Action&lt;/em&gt;&lt;br&gt;
When a user loads a form on your site, Laravel generates a unique, secret token and stores it in two places:&lt;br&gt;
In the user's Session (on the server).&lt;br&gt;
In a hidden input field (_token) within the HTML form.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Verification&lt;/em&gt;&lt;br&gt;
When the user submits the form, Laravel compares the token from the hidden field to the token stored in the server's session data.&lt;/p&gt;

&lt;p&gt;If they match:&lt;br&gt;
The request is safe and proceeds.&lt;/p&gt;

&lt;p&gt;If they don't match (or the token is missing):&lt;br&gt;
Laravel blocks the request with a 419 Page Expired error.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Encryption&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What it is&lt;/em&gt;&lt;br&gt;
Encryption ensures that any session information sent to the browser is unreadable to hackers, whether it's the session ID or actual session data.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How Laravel Protects You&lt;/em&gt;&lt;br&gt;
1- Key Security:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Laravel uses a long, random and secret string defined in your &lt;strong&gt;.env&lt;/strong&gt; file as the &lt;strong&gt;APP_KEY&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;This secret key is the only key used to encrypt and decrypt the session contents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2- The Process:&lt;br&gt;
Depending on the session driver, Laravel encrypts either just the Session ID or the entire session data before storing it in the browser cookie.&lt;/p&gt;

&lt;p&gt;3- Result: &lt;br&gt;
Even if attacker:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Intercepts cookie → sees encrypted session ID&lt;/li&gt;
&lt;li&gt;Accesses server files → sees encrypted session data&lt;/li&gt;
&lt;li&gt;Steals session file → cannot read contents without &lt;strong&gt;APP_KEY&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;Session ID Regeneration (Preventing Session Fixation)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What it prevents&lt;/em&gt;&lt;br&gt;
Session hijacking - when hackers steal your login session&lt;/p&gt;

&lt;p&gt;&lt;em&gt;How it works&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you login, Laravel creates a completely new session ID.&lt;/li&gt;
&lt;li&gt;Old session ID becomes useless.&lt;/li&gt;
&lt;li&gt;Hackers can't use old ID to access your account.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Result&lt;/em&gt;&lt;br&gt;
Even if an attacker knew the old ID, that ID is now invalid and useless, as the user is authenticated under the new, secret ID. This makes hijacking the authenticated session impossible using the old ID.&lt;/p&gt;




</description>
      <category>backend</category>
      <category>laravel</category>
      <category>php</category>
    </item>
    <item>
      <title>Laravel Real-time</title>
      <dc:creator>ashrakt</dc:creator>
      <pubDate>Sun, 14 Sep 2025 00:33:03 +0000</pubDate>
      <link>https://forem.com/ashrakt_amin/laravel-real-time-5g48</link>
      <guid>https://forem.com/ashrakt_amin/laravel-real-time-5g48</guid>
      <description>&lt;p&gt;What Are Notifications in Laravel?&lt;br&gt;
Laravel notification is a way to send a message to your users. Think of it as a central hub for all your app's alerts. Instead of writing separate code for emails, text messages, or in-app alerts, Laravel gives you a single, clean way to handle them all. You write the message once, and Laravel sends it through whatever channels you choose.&lt;/p&gt;

&lt;p&gt;Types of Notifications&lt;br&gt;
Laravel has several built-in notification types, each for a different purpose:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Mail Notifications:&lt;br&gt;
These send a standard email. They're perfect for important updates like a new invoice or a password reset link.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Database Notifications:&lt;br&gt;
This type saves a record of the notification in your database. It's used for the notifications you see inside an app. Users can see their notification history and mark them as read.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SMS Notifications:&lt;br&gt;
send text messages directly to a user's phone. This is perfect for things that need immediate attention, like verification codes (OTP). Laravel supports this through services like Vonage and Twilio.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Slack Notifications:&lt;br&gt;
send messages to Slack channels or to team members directly. This is great for sending internal alerts, like error logs or important system updates, helping development teams stay informed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Broadcast Notifications: This is the key to real-time notifications. It sends the notification data to a service like Pusher or Laravel Echo. This allows a user's browser to get an instant alert without having to refresh the page. This is what makes real-time functionality possible.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;&lt;strong&gt;How to Send a Notification to an Admin When a New User Registers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I- Prepare the Database&lt;br&gt;
First, you need a table to save the notifications. Use this command to create a migration file:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;php artisan notifications:table&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7xs6aqfrt099d0fwsco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7xs6aqfrt099d0fwsco.png" alt=" " width="770" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, run the migration to create the table named notifications in your database:&lt;br&gt;
php artisan migrate&lt;/p&gt;



&lt;ul&gt;
&lt;li&gt;Make Your Admin Model Notifiable
By default, Laravel's User model is already notifiable. But if you have a separate Admin model, you need to add the Notifiable trait to it. This gives the Admin model the superpower to receive notifications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjzr4a7ad6kdteqiorzp.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcjzr4a7ad6kdteqiorzp.PNG" alt=" " width="746" height="339"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create the Notification class&lt;br&gt;
Next, create the notification class that will define the content. This example will create a notification for when a new user signs up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;php artisan make:notification NewUserRegisteredNotification&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the new file app/Notifications/NewUserRegisteredNotification.php.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class NewUserRegisteredNotification extends Notification
{
    use Queueable;
    public $user;

    public function __construct($newUser)
    {
        $this-&amp;gt;user = $newUser;
    }

    public function via(object $notifiable): array
    {
        return ['database'];
    }


    // public function toMail(object $notifiable): MailMessage
    // {
    //     return (new MailMessage)
    //         -&amp;gt;line('The introduction to the notification.')
    //         -&amp;gt;action('Notification Action', url('/'))
    //         -&amp;gt;line('Thank you for using our application!');
    // }


    public function toArray(object $notifiable): array
    {
        return [
            "name"    =&amp;gt; $this-&amp;gt;user-&amp;gt;name,
            "email"   =&amp;gt; $this-&amp;gt;user-&amp;gt;email,
            "message" =&amp;gt; "new user registered",
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;__construct()&lt;br&gt;
This function is the "constructor" of the class. You use it to pass any data that the notification needs before it's sent.&lt;/p&gt;

&lt;p&gt;via(object $notifiable): array&lt;br&gt;
This function determines the channels the notification will be sent through. It simply returns an array with the names of the channels you want to use, like mail, database, or slack.&lt;/p&gt;

&lt;p&gt;toMail(object $notifiable): MailMessage&lt;br&gt;
This function is specifically for email notifications. If the via() function returns mail, this function will be used to build the email message. Here, you define the subject, the body text, and any buttons that will appear in the email.&lt;/p&gt;

&lt;p&gt;toArray(object $notifiable): array&lt;br&gt;
This function is a generic way to convert the notification into an array. It's used by different channels, like database and broadcast, to either save the notification or send it as data.&lt;/p&gt;



&lt;p&gt;We want to store this notification in the database, so we'll use the database channel and define the data to be stored.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;calling notification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have just one admin to notify.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function store(Request $request): RedirectResponse
    {
        $request-&amp;gt;validate([
            'name' =&amp;gt; ['required', 'string', 'max:255'],
            'email' =&amp;gt; ['required', 'string', 'email', 'max:255', 'unique:' . User::class],
            'password' =&amp;gt; ['required', 'confirmed', Rules\Password::defaults()],
        ]);

        $user = User::create([
            'name' =&amp;gt; $request-&amp;gt;name,
            'email' =&amp;gt; $request-&amp;gt;email,
            'password' =&amp;gt; Hash::make($request-&amp;gt;password),
        ]);

        event(new Registered($user));

        $admin = Admin::find(1);
        $admin-&amp;gt;notify(new NewUserRegisteredNotification($user));

        Auth::login($user);

        return redirect(RouteServiceProvider::HOME);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;register form&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntg99sbnuqek0lhgueg5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntg99sbnuqek0lhgueg5.png" alt=" " width="707" height="563"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;notifications table&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35glf9lfprm7a88g3yn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F35glf9lfprm7a88g3yn5.png" alt=" " width="800" height="101"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;you can use another way &lt;br&gt;
&lt;code&gt;Notification::send($admin, new NewUserRegisteredNotification($user));&lt;/code&gt;&lt;/p&gt;



&lt;ul&gt;
&lt;li&gt;displaying notification 
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgk5d4j5t79iapqnrmz9i.png" alt=" " width="334" height="615"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;li class="nav-item nav-notif"&amp;gt;
            &amp;lt;a class="nav-link text-muted my-2 notificationIcon" href="./#" data-toggle="modal"
                data-target=".modal-notif"&amp;gt;
                &amp;lt;span class="fe fe-bell fe-16"&amp;gt;&amp;lt;/span&amp;gt;
                &amp;lt;span class="dot dot-md text-danger"
                    id="notificationIconCounter"&amp;gt;{{ count(Auth::guard('admin')-&amp;gt;user()-&amp;gt;unreadNotifications) }}&amp;lt;/span&amp;gt;
            &amp;lt;/a&amp;gt;
        &amp;lt;/li&amp;gt;
        {{-- Notification Modal --}}
        &amp;lt;div class="modal fade modal-notif modal-slide" tabindex="-1" role="dialog"
            aria-labelledby="defaultModalLabel" aria-hidden="true"&amp;gt;
            &amp;lt;div class="modal-dialog modal-sm" role="document"&amp;gt;
                &amp;lt;div class="modal-content"&amp;gt;
                    &amp;lt;div class="modal-header"&amp;gt;
                        &amp;lt;h5 class="modal-title" id="defaultModalLabel"&amp;gt;Notifications&amp;lt;/h5&amp;gt;
                        &amp;lt;button type="button" class="close" data-dismiss="modal" aria-label="Close"&amp;gt;
                            &amp;lt;span aria-hidden="true"&amp;gt;&amp;amp;times;&amp;lt;/span&amp;gt;
                        &amp;lt;/button&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div class="modal-body" id="notificationIconModal"&amp;gt;
                        @if (count(Auth::guard('admin')-&amp;gt;user()-&amp;gt;notifications) &amp;gt; 0)
                            &amp;lt;div class="list-group list-group-flush my-n3"&amp;gt;
                                @foreach (Auth::guard('admin')-&amp;gt;user()-&amp;gt;notifications-&amp;gt;take(5) as $notification)
                                    &amp;lt;div
                                        class="list-group-item @if ($notification-&amp;gt;unread()) bg-light @else bg-transparent @endif "&amp;gt;
                                        &amp;lt;div class="row align-items-center"&amp;gt;
                                            &amp;lt;div class="col-auto"&amp;gt;
                                                &amp;lt;span class="fe fe-box fe-24"&amp;gt;&amp;lt;/span&amp;gt;
                                            &amp;lt;/div&amp;gt;
                                            &amp;lt;div class="col"&amp;gt;
                                                {{-- &amp;lt;small&amp;gt;&amp;lt;strong&amp;gt;Package has uploaded successfull&amp;lt;/strong&amp;gt;&amp;lt;/small&amp;gt; --}}
                                                &amp;lt;div class="my-0 text-muted small"&amp;gt;
                                                    {{ $notification-&amp;gt;data['message'] }}
                                                &amp;lt;/div&amp;gt;
                                                &amp;lt;small
                                                    class="badge badge-pill badge-light text-muted"&amp;gt;{{ $notification-&amp;gt;created_at-&amp;gt;diffForHumans() }}&amp;lt;/small&amp;gt;
                                            &amp;lt;/div&amp;gt;
                                        &amp;lt;/div&amp;gt;
                                    &amp;lt;/div&amp;gt;
                                @endforeach
                            &amp;lt;/div&amp;gt;
                        @endif &amp;lt;!-- / .list-group --&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;div class="modal-footer" id="clearNotification"&amp;gt;
                        &amp;lt;button type="button" class="btn btn-secondary btn-block" data-dismiss="modal"&amp;gt;Clear
                            All&amp;lt;/button&amp;gt;
                    &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    $("document").ready(function() {
        // mark all notifications to read
        $(document).on('click', ".notificationIcon", function() {
            $.ajax({
                url: {{ Illuminate\Support\Js::from(route('admin.notifications.read')) }},
                method: 'get',
                success: function(data) {
                    $("#notificationIconCounter").load(" #notificationIconCounter &amp;gt; *");
                    $("#notificationIconModal").load(" #notificationIconModal &amp;gt; *");
                },
                error: function() {
                    alert("please try again");
                }
            });
        });



        // clear all notification
        $(document).on('click', "#clearNotification", function() {
            $.ajax({
                url: {{ Illuminate\Support\Js::from(route('admin.notifications.clear')) }},
                method: 'get',
                success: function(data) {
                    $("#notificationIconCounter").load(" #notificationIconCounter &amp;gt; *");
                    $("#notificationIconModal").load(" #notificationIconModal &amp;gt; *");
                },
                error: function() {
                    alert("please try again");
                }
            });
        });
    });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;basic configurations&lt;br&gt;
Before broadcasting any events, you will first need to register the App\Providers\BroadcastServiceProvider. In new Laravel applications, you only need to uncomment this provider in the providers array of your config/app.php configuration file. This BroadcastServiceProvider contains the code necessary to register the broadcast authorization routes and callbacks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqsmh82u7tpoj9v5av36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgqsmh82u7tpoj9v5av36.png" alt=" " width="704" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The config/broadcasting.php file is the central configuration hub for Laravel's broadcasting system. Its main role is to tell Laravel which broadcasting service to use and how to connect to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hqlvgzj5aqedm09k9h0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1hqlvgzj5aqedm09k9h0.png" alt=" " width="711" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4r56qxnxh1fes0iykeox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4r56qxnxh1fes0iykeox.png" alt=" " width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Getting Started with broadcast driver (Pusher):&lt;/p&gt;

&lt;p&gt;These are the simple steps to set up your account and get your API keys.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create Your Pusher Account&lt;br&gt;
Go to the Pusher website (pusher.com).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choose a Pusher Product&lt;br&gt;
After signing up, you'll be asked to choose a product.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Select Channels (this is the service used for Laravel's real-time events).&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsye6zkcl421y70hyxnka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsye6zkcl421y70hyxnka.png" alt=" " width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Create a New Application
You'll be prompted to Create a New App.
Name your app (e.g., laravel-broadcast-app).
Select a Cluster (a server region, like eu or us2)—choose one closest to your users for better performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9a9vcslqpihdsoasabqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9a9vcslqpihdsoasabqo.png" alt=" " width="800" height="311"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhh3wjzhnvp7ji4lrjylc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhh3wjzhnvp7ji4lrjylc.png" alt=" " width="716" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get Your App Keys
Once the app is created, you'll be taken to the App Keys section&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Copy these keys. You will need to paste them into your Laravel project's .env file to connect your application to Pusher.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq4pzs1t9zp9h4g08uup.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcq4pzs1t9zp9h4g08uup.png" alt=" " width="800" height="367"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dmk3km25gs1ym1esjg7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dmk3km25gs1ym1esjg7.png" alt=" " width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;Creating a Broadcast Event&lt;/p&gt;

&lt;p&gt;1- Generate the Event Class&lt;br&gt;
First, you need to create a new Event class using the Artisan command. We'll name this event NewUserRegisteredEvent.&lt;br&gt;
&lt;code&gt;php artisan make:event NewUserRegisteredEvent&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command creates a new file at app/Events/NewUserRegisteredEvent.php.&lt;/p&gt;

&lt;p&gt;2- Implement the Broadcast Interface&lt;br&gt;
Open the newly created file (app/Events/NewUserRegisteredEvent.php). To make any event broadcastable, its class must implement the ShouldBroadcast interface.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Use the Interface: Add use Illuminate\Contracts\Broadcasting\ShouldBroadcast;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implement: Add implements ShouldBroadcast to the class definition.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycvxaczwm9e3hkfcluk2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fycvxaczwm9e3hkfcluk2.png" alt=" " width="800" height="598"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function broadcastOn(): array
{
    return [
        new Channel('new_user_channel'),
    ];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The core function of broadcastOn() is to determine and specify the channel(s) that the event's data will be published to via the broadcasting driver.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;channels types&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;public : all users &amp;amp; guests (no Auth required).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;private : Auth users only (any guard).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;presence : Auth users only (any guard) , awareness of who is &lt;br&gt;
         subscribed to this channel.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;3- Dispatch the Event&lt;br&gt;
Finally, you need to fire the event from your Laravel code (e.g., from a Controller after a user register).&lt;/p&gt;

&lt;p&gt;These two lines of code are the ways you trigger (or "fire") the broadcasting process for your event in Laravel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
    public function store(Request $request): RedirectResponse
    {
        $request-&amp;gt;validate([
            'name' =&amp;gt; ['required', 'string', 'max:255'],
            'email' =&amp;gt; ['required', 'string', 'email', 'max:255', 'unique:' . User::class],
            'password' =&amp;gt; ['required', 'confirmed', Rules\Password::defaults()],
        ]);

        $user = User::create([
            'name' =&amp;gt; $request-&amp;gt;name,
            'email' =&amp;gt; $request-&amp;gt;email,
            'password' =&amp;gt; Hash::make($request-&amp;gt;password),
        ]);

        event(new Registered($user));

        $admin = Admin::find(1);
        // $admin-&amp;gt;notify(new NewUserRegisteredNotification($user));
        Notification::send($admin, new NewUserRegisteredNotification($user));


        // trigger (or "fire") the broadcasting process
        NewUserRegisteredEvent::dispatch($user);
        // broadcast(new NewUserRegisteredEvent($user));

        Auth::login($user);
        return redirect(RouteServiceProvider::HOME);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;recievers&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pusher &lt;/li&gt;
&lt;li&gt;Laravel Echo&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;using pusher&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1- Install the Pusher PHP SDK&lt;/p&gt;

&lt;p&gt;&lt;a href="https://laravel.com/docs/10.x/broadcasting#pusher-channels" rel="noopener noreferrer"&gt;laravel pusher documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;composer require pusher/pusher-php-server&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dashboard.pusher.com/apps/2055697/getting_started" rel="noopener noreferrer"&gt;pusher reciever&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4x8e7l2hddu1r021qkl5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4x8e7l2hddu1r021qkl5.png" alt=" " width="800" height="362"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subscribe to events on the client.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  &amp;lt;script src="https://js.pusher.com/8.2.0/pusher.min.js"&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script&amp;gt;
        // Enable pusher logging - don't include this in production
        Pusher.logToConsole = false;

        var pusher = new Pusher("{{ env('PUSHER_APP_KEY') }}", {
            cluster: 'eu'
        });

        var channel = pusher.subscribe('new_user_channel');
        channel.bind('App\\Events\\NewUserRegisteredEvent', function(data) {
            console.log(data['message']);
            let currentCount = parseInt($("#notificationIconCounter").text()) || 0;
            let newCount = currentCount + 1;
            $("#notificationIconCounter").text(newCount);
        });
    &amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-You will need to update your Laravel project's .env file &lt;code&gt;BROADCAST_DRIVER=pusher&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;test your code:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6hzr4ekbqmab98zz0tl1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6hzr4ekbqmab98zz0tl1.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2lf8s5yalbdf2kgu64z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu2lf8s5yalbdf2kgu64z.png" alt=" " width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;using Laravel Echo&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Laravel Echo is a JavaScript library that makes it painless to subscribe to channels and listen for events broadcast by your server-side broadcasting driver. You may install Echo via the NPM package manager.&lt;/p&gt;
&lt;h2&gt;
  
  
  To successfully switch to Laravel Echo, you must comment out or remove the direct Pusher client initialization script from your HTML or Blade files.
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faejw8pgwy4nax4mp5grr.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faejw8pgwy4nax4mp5grr.PNG" alt=" " width="800" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1- install package&lt;br&gt;
&lt;code&gt;npm install --save-dev laravel-echo pusher-js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;2- Configure .env &lt;br&gt;
Add your Pusher credentials (Keys, Secret, and Cluster) to your .env file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;BROADCAST_DRIVER=pusher
PUSHER_APP_ID=YOUR_APP_ID
PUSHER_APP_KEY=YOUR_APP_KEY
PUSHER_APP_SECRET=YOUR_APP_SECRET
PUSHER_APP_CLUSTER=eu or mt1 or ap2 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3- Configure Echo &lt;br&gt;
Open the file resources/js/bootstrap.js (or app.js) and uncomment the Echo block, using your .env variables via the VITE_ prefix:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfbgklq641kd0a4l00ob.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjfbgklq641kd0a4l00ob.png" alt=" " width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4- Load the compiled and necessary assets for the primary entry point file located at resources/js/app.js."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffn3tajiffyd6ng2o48pz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffn3tajiffyd6ng2o48pz.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Development run &lt;code&gt;npm run dev&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In Production run &lt;code&gt;npm run build&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;5- Listening for Events&lt;br&gt;
you are ready to start listening for events that are broadcast from your Laravel application. First, use the channel method to retrieve an instance of a channel, then call the listen method to listen for a specified event.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzr4r2lqu54v3gd8q3m0h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzr4r2lqu54v3gd8q3m0h.png" alt=" " width="800" height="493"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4mlxpc2aof79538u60ho.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4mlxpc2aof79538u60ho.png" alt=" " width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;h1&gt;
  
  
  update this example using private channel
&lt;/h1&gt;

&lt;p&gt;1- event&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Events;

use App\Models\User;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Auth;

class NewUserRegisteredEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message;

    public function __construct(public User $user)
    {
        $this-&amp;gt;message = "new user registered called $user-&amp;gt;name";
    }

    // public channel
    // public function broadcastOn(): array
    // {
    //     return [
    //         new Channel('new_user_channel'),
    //     ];
    // }

    // private channel
    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('new_user_channel'),
        ];
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;2- bootstap.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Echo from 'laravel-echo';

import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
    wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
    wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
    wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

 // private
   window.Echo.private('new_user_channel')
    .listen('NewUserRegisteredEvent', (e) =&amp;gt; {
        console.log(e);

         let currentCount = parseInt($("#notificationIconCounter").text()) || 0;
         let newCount = currentCount + 1;
         $("#notificationIconCounter").text(newCount);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;3- authorization&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq42nj6u9xcwn7n7p5dyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq42nj6u9xcwn7n7p5dyd.png" alt=" " width="698" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;the boot() method in the BroadcastServiceProvider activates the entire authorization layer for your private real-time channels. Without it, your private channels would not work because clients couldn't be authenticated to listen.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;route/channels.php
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F92p31xczrmn82o6wn03a.png" alt=" " width="800" height="405"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;a. Broadcast::channel('new_user_channel', ...)&lt;br&gt;
Broadcast::channel(): This static method tells Laravel's broadcasting system to register a new authorization rule for the channel specified in the first argument, 'new_user_channel'.&lt;/p&gt;



&lt;p&gt;b. The Authorization Callback (function ($user) { ... })&lt;br&gt;
This is the function that performs the actual security check.&lt;/p&gt;

&lt;p&gt;$user: This variable automatically contains the authenticated user model attempting to subscribe to the channel.&lt;/p&gt;

&lt;p&gt;return $user-&amp;gt;type == "super_admin";: It returns true only if the authenticated user's type attribute matches the string "super_admin".&lt;/p&gt;

&lt;p&gt;If it returns true: The user is authorized, and the broadcasting service allows them to subscribe.&lt;/p&gt;

&lt;p&gt;If it returns false: The user is denied access, and the subscription request fails with a 403 Forbidden error.&lt;/p&gt;



&lt;p&gt;c. Guard Specification (['guards' =&amp;gt; ['admin']])&lt;br&gt;
this is an optional security enhancement that specifies which authentication guard(s) should be used to retrieve the authenticated user. &lt;/p&gt;



&lt;p&gt;&lt;strong&gt;example using presence channel&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;All presence channels are also private channels; therefore, users must be authorized to access them. However, when defining authorization callbacks for presence channels, you will not return true if the user is authorized to join the channel. Instead, you should return an array of data about the user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;steps Who's Online for Admins&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This example allows any admin to see which other admins are currently viewing the dashboard in real-time.&lt;/p&gt;

&lt;p&gt;1- Generate the Event Class&lt;br&gt;
php artisan make:event NewAdminRoomEvent&lt;/p&gt;

&lt;p&gt;2- Implement the Broadcast Interface&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcapc72r5sqfoybwgtb7s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcapc72r5sqfoybwgtb7s.png" alt=" " width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3-Dispatch the Event&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; public function store(AdminLoginRequest $request)
    {
        $request-&amp;gt;authenticate('admin');

        $request-&amp;gt;session()-&amp;gt;regenerate();

        // fire broadcast event
        NewAdminRoomEvent::dispatch();

        return \to_route('admin.index');
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4-Listening for Events using laravel echo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  // presence
   window.Echo.join(`admin-room-channel`)
    .here((users) =&amp;gt; {
         console.log("here");
        console.log(users);
    })
    .joining((user) =&amp;gt; {
        console.log("joining");
        console.log(user);
    })
    .leaving((user) =&amp;gt; {
        console.log("leaving");
        console.log(user);
    })
    .error((error) =&amp;gt; {
        console.error("error");
        console.log(user);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fncj1gmxjlomtdj2wex4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fncj1gmxjlomtdj2wex4y.png" alt=" " width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;The Channel Class&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A Channel Class moves your channel authorization logic from the routes/channels.php file into a dedicated PHP class. This follows Laravel's philosophy of separation of concerns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Steps to Create a Channel Class (3 Steps)&lt;/strong&gt;&lt;br&gt;
Step 1: Create the Class&lt;br&gt;
Use the Artisan command-line tool to generate a new Channel Class. We'll use 'new user' scenario as an example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:channel NewUserChannel&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  This command will create a file at app/Broadcasting/NewUserChannel.php.
&lt;/h2&gt;

&lt;p&gt;Step 2: Implement the Authorization Logic&lt;br&gt;
Open the newly created file (app/Broadcasting/NewUserChannel.php). You'll find a single method, join. This is where you put your authorization logic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Broadcasting;

use App\Models\Admin;

class NewUserChannel
{

    public function __construct()
    {
        //
    }


    public function join(Admin $admin): array|bool
    {
        return $admin-&amp;gt;type == "super_admin";
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Step 3: Register the Class in Routes&lt;br&gt;
Now, open your channel routes file (routes/channels.php). Instead of using a closure (anonymous function), you register the class using the static ::class syntax.&lt;/p&gt;

&lt;p&gt;Your original code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Broadcast::channel('new_user_channel', function ($user) {
    return $user-&amp;gt;type == "super_admin";
}, ['guards' =&amp;gt; ['admin']]);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('new_user_channel', NewUserChannel::class , ['guards' =&amp;gt; ['admin']]);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;The Benefit of Using a Channel Class 🌟&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft01coihbzry4662jj2kz.png" alt=" " width="705" height="299"&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Broadcast Event Options&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;broadcastas() &lt;/li&gt;
&lt;li&gt;broadcastWith() &lt;/li&gt;
&lt;li&gt;broadcastWhen() &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;1- The broadcastAs() Method: Custom Event Naming&lt;br&gt;
When an event is broadcast, Laravel automatically sends it with the class name (e.g., App\Events\UserRegistered). &lt;/p&gt;

&lt;p&gt;You can override this default name using the broadcastAs() method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
    public function broadcastAs(): string
    {
        return 'New_User_Registered_Event';
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frontend Listener: On the client side, you then listen using the custom name, preceded by a dot (.):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
window.Echo.channel('new_user_channel')
    .listen(".New_User_Registered_Event", (e) =&amp;gt; {
        console.log(e);

         let currentCount = parseInt($("#notificationIconCounter").text()) || 0;
         let newCount = currentCount + 1;
         $("#notificationIconCounter").text(newCount);
    });

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;2- The broadcastWith() Method: Controlling Data&lt;br&gt;
By default, Laravel broadcasts all the public properties of your Event class. However, you often don't want to expose all data.&lt;/p&gt;

&lt;p&gt;To control exactly which data is sent , you can define the broadcastWith() method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; public $message;

    public function __construct(public User $user)
    {
        $this-&amp;gt;message = "new user registered called $user-&amp;gt;name";
    }

public function broadcastWith(): array
    {
        return [
            'name' =&amp;gt; $this-&amp;gt;user-&amp;gt;name,
            'email' =&amp;gt; $this-&amp;gt;user-&amp;gt;email,
        ];
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6la6p7fdgwjtoevb8p0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6la6p7fdgwjtoevb8p0.png" alt=" " width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;3- The broadcastWhen() method in a Laravel Event class lets you define a condition that must be true for the event to be broadcast at all. If the method returns false, the event won't be broadcast to any listeners, saving processing time and resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; public function broadcastWhen(): bool
    {
        return $this-&amp;gt;user-&amp;gt;name === 'ashrakt';
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;model broadcasting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You use Model Broadcasting when you need a real-time notification specifically because an Eloquent model was directly created, updated, or deleted in the database.&lt;/p&gt;




&lt;p&gt;Here are the steps for setting up Model Broadcasting for the Post model to handle Create, Update, and Delete events, covering both the backend (Laravel) and frontend (JavaScript) configurations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Laravel Backend&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Post Model (app/Models/Post.php)
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Models;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Broadcasting\Channel;
use Illuminate\Database\Eloquent\BroadcastsEvents;


class Post extends Model
{
    use BroadcastsEvents;
    protected $fillable = ['user_id', 'title', 'body'];


    public function user(): BelongsTo
    {
        return $this-&amp;gt;belongsTo(User::class);
    }


    public function broadcastOn(): array
    {
        return [
            new Channel('posts'),
        ];
    }


    public function broadcastAs(string $event): string
    {
        // This will produce: 'post.created', 'post.updated', or 'post.deleted'
        return 'post.' . $event;
    }


    public function broadcastWith(): array
    {
        return [
            'id' =&amp;gt; $this-&amp;gt;id,
            'title' =&amp;gt; $this-&amp;gt;title,
            'user_name' =&amp;gt; $this-&amp;gt;user-&amp;gt;name ?? 'N/A',
            'updated_at' =&amp;gt; $this-&amp;gt;updated_at-&amp;gt;diffForHumans(),
        ];
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;

class PostController extends Controller
{

    public function index()
    {
        $posts = Post::all();
        return view('posts.index', compact('posts'));
    }


    public function store(Request $request)
    {
        $validated = $request-&amp;gt;validate([
            'title' =&amp;gt; 'required|string|max:150',
            'body' =&amp;gt; 'required|string',
        ]);

        $post = Post::create([
            'user_id' =&amp;gt; Auth::id(),
            'title' =&amp;gt; $validated['title'],
            'body' =&amp;gt; $validated['body'],
        ]);

        return redirect()-&amp;gt;route('posts.index')-&amp;gt;with('success', 'تم إنشاء المنشور بنجاح.');
    }

    public function edit(Post $post)
    {
        return view('posts.edit', compact('post'));
    }

    public function update(Request $request, Post $post)
    {
        $validated = $request-&amp;gt;validate([
            'title' =&amp;gt; 'required|string|max:150',
            'body' =&amp;gt; 'required|string',
        ]);

        if (Auth::id() !== $post-&amp;gt;user_id) {
            return back()-&amp;gt;with('error', 'ليس لديك صلاحية لتعديل هذا المنشور.');
        }

        $post-&amp;gt;update($validated);

        return redirect()-&amp;gt;route('posts.index')-&amp;gt;with('success', 'تم تحديث المنشور بنجاح.');
    }


    public function destroy(Post $post)
    {
        if (Auth::id() !== $post-&amp;gt;user_id) {
            return back()-&amp;gt;with('error', 'ليس لديك صلاحية لحذف هذا المنشور.');
        }

        $post-&amp;gt;delete();

        return redirect()-&amp;gt;route('posts.index')-&amp;gt;with('success', 'تم حذف المنشور بنجاح.');
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;*&lt;em&gt;Frontend Configuration (JavaScript/Echo) *&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You must set up Laravel Echo to listen to the common channel ('posts') and handle each specific event type differently.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Echo Listener Setup (Your Blade View or JS File)
This JavaScript code listens for all three distinct events (.post.created, .post.updated, .post.deleted).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;bootstrap.js file&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import Echo from 'laravel-echo';

import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
    wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
    wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
    wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});


// model broadcasting

        // Listen to the common public channel 'posts'
window.Echo.channel('posts')
    // A. LISTEN FOR CREATE EVENT (post.created)
    .listen(".post.created", (event) =&amp;gt; {
                console.log('New Post Created:', event.title);
    // B. LISTEN FOR UPDATE EVENT (post.updated)
    }).listen('.post.updated', (event) =&amp;gt; {
                console.log('Post Updated:', event.id, event.title);
    })
    // C. LISTEN FOR DELETE EVENT (post.deleted)
   .listen('.post.deleted', (event) =&amp;gt; {
                console.log('Post Deleted:', event.id);
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;-create post &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fda2689zq9grmevhlp76c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fda2689zq9grmevhlp76c.png" alt=" " width="800" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-update post&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqcblzb5iquiwbx45w35g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqcblzb5iquiwbx45w35g.png" alt=" " width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-delete post&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslawfvu2bxk1ee3imzhx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslawfvu2bxk1ee3imzhx.png" alt=" " width="800" height="174"&gt;&lt;/a&gt;&lt;/p&gt;




</description>
      <category>backend</category>
      <category>beginners</category>
      <category>laravel</category>
      <category>php</category>
    </item>
    <item>
      <title>Authorization in Laravel</title>
      <dc:creator>ashrakt</dc:creator>
      <pubDate>Wed, 03 Sep 2025 14:46:09 +0000</pubDate>
      <link>https://forem.com/ashrakt_amin/authorization-in-laravel-4j94</link>
      <guid>https://forem.com/ashrakt_amin/authorization-in-laravel-4j94</guid>
      <description>&lt;p&gt;What Is Authorization?&lt;br&gt;
First, think about a website with different types of users, like a regular user and an admin. Authorization is the system that checks what a logged-in user is allowed to do.&lt;br&gt;
Authorization happens after a user has already logged in and been authenticated (proven who they are).&lt;/p&gt;

&lt;p&gt;In Laravel, authorization is the process of determining if a user has permission to perform a specific action. &lt;/p&gt;

&lt;p&gt;Laravel provides two main tools for this: &lt;strong&gt;Gates and Policies&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;1) Gates are the simplest way to check a user's permissions. They are perfect for general permissions that don't relate to a specific data item (model). For example, checking if a user is an "admin" or "editor".&lt;/p&gt;

&lt;p&gt;I- How to Use a Gate&lt;br&gt;
Open the app/Providers/AuthServiceProvider.php file and define your gate inside the boot() method.&lt;br&gt;
You define a Gate in your app/Providers/AuthServiceProvider.php file. It's a simple function that returns true or false.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1x5qf3azm951aambhk9.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1x5qf3azm951aambhk9.PNG" alt=" " width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here, access-admin-panel is the name of the gate, and the function inside checks if the user's is_admin property is true.&lt;/p&gt;




&lt;p&gt;II- Use the Gate&lt;br&gt;
You can use the gate anywhere in your application, like in a Controller or a Blade view.&lt;/p&gt;

&lt;p&gt;In a Controller:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp7yqifm08tw2myzlm38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqp7yqifm08tw2myzlm38.png" alt=" " width="758" height="519"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw3y0f3obf1g4f3xu7h0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzw3y0f3obf1g4f3xu7h0.png" alt=" " width="737" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzctvtjbkbhfx6826q69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzctvtjbkbhfx6826q69.png" alt=" " width="768" height="425"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;2) Policies&lt;br&gt;
Policies are used for more specific permissions that are tied to a particular data model. They are the best way to manage permissions for actions like "updating a post" or "deleting a post".&lt;/p&gt;

&lt;p&gt;Let's say you want to allow a user to only update the posts they have created themselves.&lt;/p&gt;

&lt;p&gt;I- Create the Policy:&lt;br&gt;
Use the Artisan command to create a policy for your Post model.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;php artisan make:policy PostPolicy --model=Post&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command creates a new file at app/Policies/PostPolicy.php with built-in methods like view, create, update, and delete.&lt;/p&gt;




&lt;p&gt;II- Write the Policy Logic:&lt;br&gt;
In PostPolicy.php, add your logic to the update method to check if the user is the owner of the post.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57j1vvkctd7tjpiqvdzc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F57j1vvkctd7tjpiqvdzc.png" alt=" " width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The update method receives the User and the Post, returns true only if the user's ID matches the post's user_id.&lt;/p&gt;




&lt;p&gt;III- Register the Policy:&lt;/p&gt;

&lt;p&gt;Tell Laravel to use this policy for the Post model in app/Providers/AuthServiceProvider.php.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frb40dczepd4x23xdqmgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frb40dczepd4x23xdqmgg.png" alt=" " width="800" height="342"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;IIII- Use the Policy:&lt;/p&gt;

&lt;p&gt;-In a Controller:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gktqzomvgsji0e0uauv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gktqzomvgsji0e0uauv.png" alt=" " width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if the policy return true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwql6b38xujnjvfa2jy52.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwql6b38xujnjvfa2jy52.png" alt=" " width="769" height="582"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if return false&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wbs6dilq48016k51ut3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7wbs6dilq48016k51ut3.png" alt=" " width="720" height="392"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Spatie Laravel Permission package:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you need to manage different user roles (admin, editor, subscriber,...) and assign permissions to those roles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When you have many permissions (create posts, edit posts, delete posts, publish posts, unpublish posts), managing them in a Policy becomes repetitive. Packages allow you to define and manage these permissions in the database, making them easier to add, remove, and assign.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If your application needs to allow an admin to create and manage custom roles and permissions through a user interface, a package is a must. Policies are static PHP classes that must be updated manually by a developer. A package stores all permissions in the database, allowing for dynamic management without touching the code.&lt;br&gt;
        ---------------------------------------------&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;how to use:&lt;/p&gt;

&lt;p&gt;I- Install the Package&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;composer require spatie/laravel-permission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After the package is installed, you need to publish the migration     file and run it to create the necessary database tables.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="permission-migrations"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;php artisan migrate&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will create new tables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;permissions: This table stores all your permissions (e.g., edit posts, delete users).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;roles: This table stores all your roles (e.g., admin, writer, subscriber).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;model_has_permissions: This is a pivot table that links users directly to permissions. This allows you to give a user a permission without assigning them a role.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;model_has_roles: This is a pivot table that links users to roles. A user can have many roles, and a role can be assigned to many users.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;role_has_permissions: This is a pivot table that links roles to permissions. It allows a role to have many permissions and a permission to be assigned to many roles.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;II- Prepare the User Model&lt;br&gt;
Open the app/Models/User.php file and add the HasRoles trait.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6hm28tpw49wlp5rg1hdv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6hm28tpw49wlp5rg1hdv.png" alt=" " width="630" height="349"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;III-  Create Roles and Permissions&lt;br&gt;
you need to create your roles and permissions. You can do this with a seeder file.&lt;/p&gt;

&lt;p&gt;Run this command to make a seeder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;php artisan make:seeder RolesAndPermissionsSeeder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the new seeder file at database/seeders/RolesAndPermissionsSeeder.php and add your code to create roles like admin and permissions like edit posts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlm0m5vicp8sun0tpb5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdlm0m5vicp8sun0tpb5j.png" alt=" " width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fguz5kujg934s2haa5ea3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fguz5kujg934s2haa5ea3.png" alt=" " width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you write the code, run the seeder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;php artisan db:seed --class=RolesAndPermissionsSeeder&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-permissions table&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ffz0tt0s812lq9pxtgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ffz0tt0s812lq9pxtgf.png" alt=" " width="430" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-roles table&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o5562rewzfs1offceqj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2o5562rewzfs1offceqj.png" alt=" " width="187" height="84"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-role_has_permissions table&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggeoswshrwxo9s1bpyrr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fggeoswshrwxo9s1bpyrr.png" alt=" " width="195" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;-model_has_roles table&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftg45vw8m92upenfamm5l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftg45vw8m92upenfamm5l.png" alt=" " width="253" height="100"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;IIII- Use Permissions in Your API&lt;/p&gt;

&lt;p&gt;Go to your routes/api.php file. You can protect a route by adding the permission or role middleware. This middleware checks the user's permissions before the code even runs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sp44xtc989oxvw1mxog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4sp44xtc989oxvw1mxog.png" alt=" " width="700" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 'auth:sanctum' part makes sure the user is logged in first. The 'permission:...' part then checks if they have the right to do that action.&lt;/p&gt;

&lt;p&gt;you need to register the role and permission middleware aliases.&lt;br&gt;
Open the app/Http/Kernel.php file in your project.&lt;br&gt;
Find the $middlewareAliases array.&lt;br&gt;
Add the following two lines to the array. They link the middleware aliases to the correct classes from the Spatie package.&lt;/p&gt;

&lt;p&gt;if user writer :&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2w61igr9gvixm264udz0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2w61igr9gvixm264udz0.png" alt=" " width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;if admin :&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmey4fsacohymoy6tjd1h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmey4fsacohymoy6tjd1h.png" alt=" " width="735" height="357"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also check permissions inside controller.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73u49zu9m1wy0wpbrkqo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F73u49zu9m1wy0wpbrkqo.png" alt=" " width="799" height="649"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If the authenticated user doesn't have edit posts permission.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa80bcy30ifdkasf7qo8r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa80bcy30ifdkasf7qo8r.png" alt=" " width="687" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;else&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5roo253xj62crjl75xy1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5roo253xj62crjl75xy1.png" alt=" " width="709" height="566"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;if you have both admin and writer roles that should have the same edit permission, the best way to protect your API is with a single middleware check on the route.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxefeou2v1th5qmtgxlc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmxefeou2v1th5qmtgxlc.png" alt=" " width="647" height="84"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;You should use your code (specifically, a seeder) for the initial setup of your main roles and permissions.&lt;br&gt;
However, for managing roles and permissions daily from a UI, you should not edit your code. Instead, you'll manage everything through a dedicated API. This is one of the main reasons to use a package like Spatie.&lt;/p&gt;

&lt;p&gt;Managing from a UI via an API&lt;/p&gt;

&lt;p&gt;Here’s a simple example of what a controller method for your API would look like to assign a role to a user based on a UI request.&lt;/p&gt;

&lt;p&gt;I- api&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmflwndo1tut03u1khoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmflwndo1tut03u1khoy.png" alt=" " width="720" height="246"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;II- Update User's Role&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60qz5b255n4arxq75xoy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60qz5b255n4arxq75xoy.png" alt=" " width="800" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiojebmxymx2q28xfzuik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiojebmxymx2q28xfzuik.png" alt=" " width="708" height="478"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;III- Update Role's Permissions&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ke01ro59zew98usa88x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ke01ro59zew98usa88x.png" alt=" " width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd7x2d7gwsnmto5jctyvt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd7x2d7gwsnmto5jctyvt.png" alt=" " width="672" height="484"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;IIII- Update User's Permissions&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyafew9bkhijxvos2sjku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyafew9bkhijxvos2sjku.png" alt=" " width="800" height="394"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjchfvv0mtc157o26c1ox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjchfvv0mtc157o26c1ox.png" alt=" " width="734" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;model_has_permissions table&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfwr51oghk76pvsegru5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfwr51oghk76pvsegru5.png" alt=" " width="385" height="94"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;thanks...&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>backenddevelopment</category>
    </item>
    <item>
      <title>Laravel Export and download Excel File</title>
      <dc:creator>ashrakt</dc:creator>
      <pubDate>Sat, 28 Sep 2024 20:31:41 +0000</pubDate>
      <link>https://forem.com/ashrakt_amin/laravel-export-and-download-excel-file-218d</link>
      <guid>https://forem.com/ashrakt_amin/laravel-export-and-download-excel-file-218d</guid>
      <description>&lt;p&gt;1: Install maatwebsite/excel Package :&lt;/p&gt;

&lt;p&gt;composer require maatwebsite/excel &lt;/p&gt;

&lt;p&gt;2: php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider" --tag=config&lt;/p&gt;

&lt;p&gt;3: php artisan make:export UsersExport --model=User&lt;/p&gt;

&lt;p&gt;4:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;?php

namespace App\Exports;

use App\Models\User;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Maatwebsite\Excel\Concerns\WithMapping;


class UsersExport implements FromCollection, WithHeadings, WithStyles  ,WithMapping ,WithColumnWidths
{

    public function collection()
    {
        return User::select("id", "name", "email")-&amp;gt;get();

    }


 public function map($user): array
    {   
        return [
            $user-&amp;gt;id,
            $user-&amp;gt;name,
            $user-&amp;gt;email,
        ];
    }


    public function headings(): array
    {
        return ["ID", "Name", "Email"];
    }




     public function columnWidths(): array
    {
        return [
            'A' =&amp;gt; 5, 
            'B' =&amp;gt; 5,
            'C' =&amp;gt; 12, 
        ];
    }


    public function styles(Worksheet $sheet)
    {
        return [
            // Apply styles to the first row (headers)
            1 =&amp;gt; [
                'font' =&amp;gt; [
                    'bold' =&amp;gt; true,
                    'color' =&amp;gt; ['rgb' =&amp;gt; '80000F'],
                    'size' =&amp;gt; 12,
                ],
                'fill' =&amp;gt; [
                    'fillType' =&amp;gt; \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                    'startColor' =&amp;gt; ['rgb' =&amp;gt; 'EFE1E3'],
                ],
            ],
        ];
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;5: Create Controller&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Maatwebsite\Excel\Facades\Excel;
use App\Models\User;
use App\Exports\UsersExport;
use Carbon\Carbon;
use Illuminate\Support\Facades\Response;


class UserController extends Controller
{

 public function downloadUser()
    {
        $currentDate = Carbon::now()-&amp;gt;format('Y-m-d'); 

        $fileName = 'users_' . $currentDate . '.xlsx';

        Excel::store(new UsersExport, 'exports/' . $fileName);

        $filePath = storage_path('app/exports/' . $fileName);

        if (file_exists($filePath)) {

             $headers = array('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');

        return Response::download( $filePath, $fileName , $headers)-&amp;gt;deleteFileAfterSend(true);

         }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptfqkq04ziyevw590kih.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fptfqkq04ziyevw590kih.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>integrate Google Maps into a Laravel application using JavaScript</title>
      <dc:creator>ashrakt</dc:creator>
      <pubDate>Mon, 06 May 2024 11:46:36 +0000</pubDate>
      <link>https://forem.com/ashrakt_amin/creating-a-map-with-laravel-3964</link>
      <guid>https://forem.com/ashrakt_amin/creating-a-map-with-laravel-3964</guid>
      <description>&lt;ol&gt;
&lt;li&gt;place controller
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Controllers;

use App\Models\Place;
use Illuminate\Http\Request;

class PlaceController extends Controller
{
    public function index()
    {
        $places = Place::all();

        return view('places.index', compact('places'));
    }

    public function create()
    {
        return view('places.create');
    }

    public function store(Request $request)
    {
        // Validate the request data as per your requirements
        $validatedData = $request-&amp;gt;validate([
            'name' =&amp;gt; 'required',
            'latitude' =&amp;gt; 'required',
            'longitude' =&amp;gt; 'required',
        ]);

        Place::create($validatedData);

        return redirect()-&amp;gt;route('places.index')-&amp;gt;with('success', 'Location created successfully');
    }

    public function show(Place $place)
    {
        return view('places.show', compact('place'));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;index blade
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@extends('layouts.app')

@section('content')

&amp;lt;a href="{{ route('places.create') }}" class="btn btn-primary mt-5 ml-5"&amp;gt;Add Location&amp;lt;/a&amp;gt;

&amp;lt;div class="container d-flex justify-content-center"&amp;gt;
    &amp;lt;table class="table mt-1" style="width:60%"&amp;gt;
        &amp;lt;thead&amp;gt;
            &amp;lt;tr&amp;gt;
                &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Latitude&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Longitude&amp;lt;/th&amp;gt;
                &amp;lt;th&amp;gt;Actions&amp;lt;/th&amp;gt;
            &amp;lt;/tr&amp;gt;
        &amp;lt;/thead&amp;gt;
        &amp;lt;tbody&amp;gt;
            @foreach ($places as $place)
            &amp;lt;tr&amp;gt;
                &amp;lt;td&amp;gt;{{ $place-&amp;gt;name }}&amp;lt;/td&amp;gt;
                &amp;lt;td&amp;gt;{{ $place-&amp;gt;latitude }}&amp;lt;/td&amp;gt;
                &amp;lt;td&amp;gt;{{ $place-&amp;gt;longitude }}&amp;lt;/td&amp;gt;
                &amp;lt;td&amp;gt;
                    &amp;lt;a href="{{ route('places.show', $place-&amp;gt;id) }}" class="btn btn-primary"&amp;gt;View&amp;lt;/a&amp;gt;
                &amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
            @endforeach
        &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
&amp;lt;/div&amp;gt;
@endsection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;create blade
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@extends('layouts.app')

@section('content')
&amp;lt;h3 class="text-center m-3"&amp;gt;Add Location&amp;lt;/h3&amp;gt;

&amp;lt;div class="container"&amp;gt;
    &amp;lt;form id="location-form" action="{{ route('places.store') }}" method="POST"&amp;gt;
        @csrf
        &amp;lt;input type="hidden" name="latitude" id="latitude" required&amp;gt;
        &amp;lt;input type="hidden" name="longitude" id="longitude" required&amp;gt;

        &amp;lt;div class="form-group"&amp;gt;
            &amp;lt;label for="place"&amp;gt;Place&amp;lt;/label&amp;gt;
            &amp;lt;input type="text" id="place" name="name" class="form-control" placeholder="Search for a place" required&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" class="btn btn-primary mb-3"&amp;gt;Save&amp;lt;/button&amp;gt;
    &amp;lt;/form&amp;gt;

    &amp;lt;div id="map" style="height: 300px;"&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;/div&amp;gt;

&amp;lt;script src="https://maps.googleapis.com/maps/api/js?key={{ env('GOOGLE_MAPS_API_KEY') }}&amp;amp;libraries=places&amp;amp;callback=initMap" async defer&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
    function initMap() {
        var map = new google.maps.Map(document.getElementById('map'), {
            center: {
                lat: 0,
                lng: 0
            },
            zoom: 2
        });

        var input = document.getElementById('place');
        var searchBox = new google.maps.places.SearchBox(input);

        map.addListener('bounds_changed', function() {
            searchBox.setBounds(map.getBounds());
        });

        var marker;

        searchBox.addListener('places_changed', function() {
            var places = searchBox.getPlaces();

            if (places.length === 0) {
                return;
            }

            var bounds = new google.maps.LatLngBounds();

            places.forEach(function(place) {
                if (!place.geometry) {
                    console.log("Returned place contains no geometry");
                    return;
                }

                if (marker) {
                    marker.setMap(null);
                }

                marker = new google.maps.Marker({
                    map: map,
                    position: place.geometry.location,
                    draggable: true
                });

                google.maps.event.addListener(marker, 'dragend', function(event) {
                    document.getElementById('latitude').value = event.latLng.lat();
                    document.getElementById('longitude').value = event.latLng.lng();
                });

                google.maps.event.addListener(map, 'click', function(event) {
                    marker.setPosition(event.latLng);
                    document.getElementById('latitude').value = event.latLng.lat();
                    document.getElementById('longitude').value = event.latLng.lng();
                });

                if (place.geometry.viewport) {
                    bounds.union(place.geometry.viewport);
                } else {
                    bounds.extend(place.geometry.location);
                }
            });

            map.fitBounds(bounds);
        });
    }
&amp;lt;/script&amp;gt;
@endsection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;show blade
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@extends('layouts.app')

@section('content')

&amp;lt;div class="container d-flex justify-content-center mt-5"&amp;gt;
    &amp;lt;table class="table mt-3" style="width:50%"&amp;gt;
        &amp;lt;tbody&amp;gt;
            &amp;lt;tr&amp;gt;
                &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
                &amp;lt;td&amp;gt;{{ $place-&amp;gt;name }}&amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
            &amp;lt;tr&amp;gt;
                &amp;lt;th&amp;gt;Latitude&amp;lt;/th&amp;gt;
                &amp;lt;td&amp;gt;{{ $place-&amp;gt;latitude }}&amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
            &amp;lt;tr&amp;gt;
                &amp;lt;th&amp;gt;Longitude&amp;lt;/th&amp;gt;
                &amp;lt;td&amp;gt;{{ $place-&amp;gt;longitude }}&amp;lt;/td&amp;gt;
            &amp;lt;/tr&amp;gt;
        &amp;lt;/tbody&amp;gt;
    &amp;lt;/table&amp;gt;
    &amp;lt;div class="container d-flex justify-content-center mt-3"&amp;gt;
        &amp;lt;div class="d-flex justify-content-center" id="map" style="height: 300px;width:50%;" data-latitude="{{ $place-&amp;gt;latitude }}" data-longitude="{{ $place-&amp;gt;longitude }}"&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
    function initMap() {
        var latitude = document.getElementById('map').dataset.latitude;
        var longitude = document.getElementById('map').dataset.longitude;
        var location = {
            lat: parseFloat(latitude),
            lng: parseFloat(longitude)
        };

        var map = new google.maps.Map(document.getElementById('map'), {
            center: location,
            zoom: 12
        });

        var marker = new google.maps.Marker({
            map: map,
            position: location
        });
    }
&amp;lt;/script&amp;gt;

&amp;lt;script src="https://maps.googleapis.com/maps/api/js?key={{ env('GOOGLE_MAPS_API_KEY') }}&amp;amp;callback=initMap" async defer&amp;gt;&amp;lt;/script&amp;gt;

@endsection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Social Login with Laravel Socialite (Google , facebook , github)</title>
      <dc:creator>ashrakt</dc:creator>
      <pubDate>Sat, 06 Apr 2024 13:34:15 +0000</pubDate>
      <link>https://forem.com/ashrakt_amin/social-login-with-laravel-socialite-google-and-facebook-37eg</link>
      <guid>https://forem.com/ashrakt_amin/social-login-with-laravel-socialite-google-and-facebook-37eg</guid>
      <description>&lt;p&gt;Laravel Socialite is an official Laravel package that provides a simple and convenient way to authenticate users with third-party services, such as Facebook, GitHub, Google, Twitter, and more. It abstracts the complexities of the OAuth authentication process and provides a unified API for authentication with various social platforms.&lt;/p&gt;

&lt;p&gt;create a new Laravel project via Composer's create-project&lt;br&gt;
&lt;code&gt;$ composer create-project laravel/laravel:^10.0 SocialLogin&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Step 1: Install Laravel Socialite&lt;/strong&gt;&lt;br&gt;
Start by installing Laravel Socialite via Composer. Open your terminal and navigate to your Laravel project directory, then run the following command:&lt;br&gt;
&lt;code&gt;composer require laravel/socialite&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: &lt;a href="https://socialiteproviders.com/about/" rel="noopener noreferrer"&gt;Socialite Providers&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
SocialiteProviders is a collection of OAuth 1 &amp;amp; 2 packages that extend Laravel Socialite.&lt;br&gt;
The Observer Pattern is used by the Manager package to extend Socialite.&lt;br&gt;
This allows numerous providers to be used in addition to the ones provided by Laravel Socialite&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google ,facebook ,github provider&lt;/strong&gt;&lt;br&gt;
1:&lt;br&gt;
&lt;code&gt;composer require socialiteproviders/google&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;code&gt;composer require socialiteproviders/facebook&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;code&gt;composer require socialiteproviders/github&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
2:Add configuration to config/services.php&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

'google' =&amp;gt; [    
  'client_id' =&amp;gt; env('GOOGLE_CLIENT_ID'),  
  'client_secret' =&amp;gt; env('GOOGLE_CLIENT_SECRET'),  
  'redirect' =&amp;gt; 'auth/google/callback'
],
'facebook' =&amp;gt; [    
  'client_id' =&amp;gt; env('FACEBOOK_CLIENT_ID'),  
  'client_secret' =&amp;gt; env('FACEBOOK_CLIENT_SECRET'),  
  'redirect' =&amp;gt; env('FACEBOOK_REDIRECT_URI') 
],
'github' =&amp;gt; [    
  'client_id' =&amp;gt; env('GITHUB_CLIENT_ID'),  
  'client_secret' =&amp;gt; env('GITHUB_CLIENT_SECRET'),  
  'redirect' =&amp;gt; env('GITHUB_REDIRECT_URI') 
],



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;3:Configure google API credentials&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://console.cloud.google.com/welcome" rel="noopener noreferrer"&gt;google&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/" rel="noopener noreferrer"&gt;facebook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/settings/developers" rel="noopener noreferrer"&gt;github&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fel7xmx1mq38xx4qc0c2z.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fel7xmx1mq38xx4qc0c2z.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanmfr53j68csys5kk6ph.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanmfr53j68csys5kk6ph.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzph6zmrtp7kyy51fekog.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzph6zmrtp7kyy51fekog.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw97o3u5xiugxfhsx20ln.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw97o3u5xiugxfhsx20ln.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiafx1rfmhyvjpvuy2o0t.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiafx1rfmhyvjpvuy2o0t.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofs2vp9iaks2136dpcf9.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fofs2vp9iaks2136dpcf9.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;click &lt;br&gt;
sava and continue&lt;br&gt;
back to dashboard&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feb5a5ux48xpzmqjjkzhd.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feb5a5ux48xpzmqjjkzhd.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1y0iu7pib80cq4b4fl2h.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1y0iu7pib80cq4b4fl2h.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nra0dv1rnwxk7p5pfmx.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1nra0dv1rnwxk7p5pfmx.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12fp791dcmpdwzziqxfg.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12fp791dcmpdwzziqxfg.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4:add your client id and secret in env &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

GOOGLE_CLIENT_ID=##########
GOOGLE_CLIENT_SECRET=##########
GOOGLE_REDIRECT_URI=##########

GITHUB_CLIENT_ID=##########
GITHUB_CLIENT_SECRET=##########
GITHUB_REDIRECT_URI=##########

FACEBOOK_CLIENT_ID=##########
FACEBOOK_CLIENT_SECRET=##########
FACEBOOK_REDIRECT_URI=##########



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;5:create Social Login Controller&lt;br&gt;
&lt;code&gt;php artisan make:Controller Auth/SocialLoginController&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
6:web&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Route::get('login', [LoginController::class, 'loginCreate']);
Route::post('login', [LoginController::class, 'login'])-&amp;gt;name('login');

Route::get('auth/{provider}/redirect', [SocialLoginController::class , 'redirect'])-&amp;gt;name('auth.socialite.redirect');
Route::get('auth/{provider}/callback', [SocialLoginController::class , 'callback'])-&amp;gt;name('auth.socialite.callback');

Route::middleware("auth")-&amp;gt;group(function () {
    Route::get('/', function () {
        return 'welcome ';
    })-&amp;gt;name('home');
});



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;7:update user table&lt;br&gt;
&lt;code&gt;php artisan make:migration add_social_provider_columns_to_users_table&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

   public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table-&amp;gt;string('provider_name')-&amp;gt;nullable();
            $table-&amp;gt;string('provider_id')-&amp;gt;nullable();
            $table-&amp;gt;string('provider_token',500)-&amp;gt;nullable();
        });
    }


    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table-&amp;gt;dropColumn(['provider_name', 'provider_id', 'provider_token']);
        });
    }


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;8:update User model&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    protected $fillable = [
        'name',
        'email',
        'password',
        'provider_name',
        'provider_id',
    ];


    protected $hidden = [
        'password',
        'remember_token',
        'provider_token'

    ];


    protected $casts = [
        'email_verified_at' =&amp;gt; 'datetime',
        'password' =&amp;gt; 'hashed',
    ];

    public function setProviderTokenAttribute($value){
        return $this-&amp;gt;attributes['provider_token'] = Crypt::crypt($value);
    }

    public function getProviderTokenAttribute($value)
    {
        return Crypt::decrypt($value);
    }
}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;9:Social Login Controller&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?php

namespace App\Http\Controllers\Auth;

use App\Models\User;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Laravel\Socialite\Facades\Socialite;
use Nette\Utils\Random;

class SocialLoginController extends Controller
{
    public function redirect($provider)
    {
        return Socialite::driver($provider)-&amp;gt;redirect();
    }

    public function callback($provider)
    {
        $user = Socialite::driver($provider)-&amp;gt;user();
        $existingUser = User::where('email', $user-&amp;gt;email)-&amp;gt;first();
        // dd($user);
        if ($existingUser) {
            Auth::login($existingUser);
        } else {

            User::create([
                'name'          =&amp;gt; $user-&amp;gt;name,
                'email'         =&amp;gt; $user-&amp;gt;email,
                'password'      =&amp;gt; Hash::make(Str::random(8)),
                'provider_name' =&amp;gt; $provider,
                'provider_id'   =&amp;gt; $user-&amp;gt;id,
                'provider_token' =&amp;gt; $user-&amp;gt;token
            ]);
        }
        return view('welcome');
    }
}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;10:login.blade.php&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

  &amp;lt;section class="vh-100"&amp;gt;
    &amp;lt;div class="container-fluid h-custom"&amp;gt;
        &amp;lt;div class="row d-flex justify-content-center align-items-center h-100"&amp;gt;
            &amp;lt;div class="col-md-9 col-lg-6 col-xl-5"&amp;gt;
                &amp;lt;img src="https://mdbcdn.b-cdn.net/img/Photos/new-templates/bootstrap-login-form/draw2.webp" class="img-fluid" alt="Sample image"&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class="col-md-8 col-lg-6 col-xl-4 offset-xl-1"&amp;gt;
                &amp;lt;div class="d-flex flex-row align-items-center justify-content-center justify-content-lg-start row mt-5"&amp;gt;
                    &amp;lt;div class="col-5"&amp;gt;
                        &amp;lt;p class="lead fw-normal mb-0 me-3"&amp;gt;Sign in with&amp;lt;/p&amp;gt;
                    &amp;lt;/div&amp;gt;

                    &amp;lt;div class="col-2"&amp;gt;
                        &amp;lt;a href="{{route('auth.socialite.redirect','google')}}"&amp;gt;
                            &amp;lt;i class="fab fa-google"&amp;gt;&amp;lt;/i&amp;gt;
                        &amp;lt;/a&amp;gt;
                    &amp;lt;/div&amp;gt;

                    &amp;lt;div class="col-2"&amp;gt;
                        &amp;lt;a href="{{route('auth.socialite.redirect','facebook')}}"&amp;gt;
                            &amp;lt;i class="fab fa-facebook"&amp;gt;&amp;lt;/i&amp;gt;
                        &amp;lt;/a&amp;gt;
                    &amp;lt;/div&amp;gt;

                    &amp;lt;div class="col-2"&amp;gt;
                        &amp;lt;a href="{{route('auth.socialite.redirect','github')}}"&amp;gt;
                            &amp;lt;i class="fab fa-github"&amp;gt;&amp;lt;/i&amp;gt;
                        &amp;lt;/a&amp;gt;
                    &amp;lt;/div&amp;gt;
                &amp;lt;/div&amp;gt;

                &amp;lt;div class="divider d-flex align-items-center my-4"&amp;gt;
                    &amp;lt;p class="text-center fw-bold mx-3 mb-0"&amp;gt;Or&amp;lt;/p&amp;gt;
                &amp;lt;/div&amp;gt;

                &amp;lt;form action="{{route('login')}}" method="POST"&amp;gt;
                    @csrf
                    &amp;lt;!-- Email input --&amp;gt;
                    &amp;lt;div class="form-outline mb-4"&amp;gt;
                        &amp;lt;input type="email" name="email" id="form3Example3" class="form-control form-control-lg" placeholder="Enter a valid email address" /&amp;gt;
                    &amp;lt;/div&amp;gt;

                    &amp;lt;!-- Password input --&amp;gt;
                    &amp;lt;div class="form-outline mb-3"&amp;gt;
                        &amp;lt;input type="password" name="password" id="form3Example4" class="form-control form-control-lg" placeholder="Enter password" /&amp;gt;
                    &amp;lt;/div&amp;gt;

                    &amp;lt;div class="d-flex justify-content-between align-items-center"&amp;gt;
                        &amp;lt;!-- Checkbox --&amp;gt;
                        &amp;lt;div class="form-check mb-0"&amp;gt;
                            &amp;lt;input class="form-check-input me-2" type="checkbox" value="" id="form2Example3" /&amp;gt;
                            &amp;lt;label class="form-check-label" for="form2Example3"&amp;gt;
                                Remember me
                            &amp;lt;/label&amp;gt;
                        &amp;lt;/div&amp;gt;
                        &amp;lt;a href="#!" class="text-body"&amp;gt;Forgot password?&amp;lt;/a&amp;gt;
                    &amp;lt;/div&amp;gt;

                    &amp;lt;div class="text-center text-lg-start mt-4 pt-2"&amp;gt;
                        &amp;lt;button type="submit" class="btn btn-primary btn-lg" style="padding-left: 2.5rem; padding-right: 2.5rem;"&amp;gt;Login&amp;lt;/button&amp;gt;
                        &amp;lt;p class="small fw-bold mt-2 pt-1 mb-0"&amp;gt;Don't have an account? &amp;lt;a href="#!" class="link-danger"&amp;gt;Register&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;
                    &amp;lt;/div&amp;gt;

                &amp;lt;/form&amp;gt;
            &amp;lt;/div&amp;gt;

        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;

&amp;lt;/section&amp;gt;




&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>laravel</category>
      <category>backend</category>
    </item>
    <item>
      <title>create an Auth module with laravel using nwidart/laravel-modules package</title>
      <dc:creator>ashrakt</dc:creator>
      <pubDate>Thu, 29 Feb 2024 07:33:05 +0000</pubDate>
      <link>https://forem.com/ashrakt_amin/create-a-modular-with-laravel-using-nwidartlaravel-modules-package-gg6</link>
      <guid>https://forem.com/ashrakt_amin/create-a-modular-with-laravel-using-nwidartlaravel-modules-package-gg6</guid>
      <description>&lt;p&gt;&lt;strong&gt;nwidart/laravel-modules&lt;/strong&gt; is a Laravel package which was created to manage your large Laravel app using modules.&lt;br&gt;
A module is like a Laravel package, it has some views, controllers or models.&lt;/p&gt;

&lt;p&gt;1) create project and install nwidart/laravel-modules package&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;create Laravel project&lt;br&gt;
&lt;code&gt;composer create-project laravel/laravel module&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;install nwidart through Composer, by run the following command:&lt;br&gt;
&lt;code&gt;composer require nwidart/laravel-modules&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The package will automatically register a service provider and alias.&lt;br&gt;
Optionally, publish the package's configuration file by running:&lt;br&gt;
&lt;code&gt;php artisan vendor:publish --provider="Nwidart\Modules\LaravelModulesServiceProvider"&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;2) Autoloading&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;By default the module classes are not loaded automatically. You can autoload your modules using psr-4. For example :&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{
  "autoload": {
    "psr-4": {
      "App\\": "app/",
      "Modules\\": "Modules/"
    }
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt; run 
&lt;code&gt;composer dump-autoload&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;3)  Generate a new module using the Nwidart package&lt;br&gt;
&lt;code&gt;php artisan module:make &amp;lt;module-name&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;php artisan module:make Auth&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

app/
bootstrap/
vendor/
Modules/
  ├── Auth/
      ├── Assets/
      ├── Config/
      ├── Console/
      ├── Database/
          ├── Migrations/
          ├── Seeders/
      ├── Entities/
      ├── Http/
          ├── Controllers/
          ├── Middleware/
          ├── Requests/
          ├── routes.php
      ├── Providers/
          ├── BlogServiceProvider.php
      ├── Resources/
          ├── lang/
          ├── views/
      ├── Repositories/
      ├── Tests/
      ├── composer.json
      ├── module.json
      ├── start.php


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2n58su5t7gb3i7puqlvw.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2n58su5t7gb3i7puqlvw.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4) install sanctun&lt;br&gt;
&lt;code&gt;composer require laravel/sanctum&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;5) Publish the Laravel Sanctum configuration file.&lt;br&gt;
&lt;code&gt;php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"&lt;br&gt;
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;6) Create the authentication controllers within the Auth module.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

php artisan module:controller LogoutController Auth
php artisan module:controller RegisterControl Auth
php artisan module:controller LoginController Auth
php artisan module:controller ForgotPasswordController Auth
php artisan module:controller ResetPasswordController Auth



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;7) Define the routes for authentication within the Auth module.&lt;br&gt;
Create a file named routes/api.php within the Modules/Auth directory and add the following code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


Route::prefix('user')-&amp;gt;group(function () {
    Route::post('register', [RegisterController::class,'register']);
    Route::post('login', [LoginController::class,'login']);
    Route::post('password/forgot ', [ForgotPasswordController::class, 'sendForgotLinkEmail']);
    Route::post('password/forgot/submit', [ForgotPasswordController::class, 'submitForgotPassword']);
    Route::post('password/reset', [ResetPasswordController::class, 'resetPassword'])-&amp;gt;middleware(['auth:sanctum']);
    Route::post('logout', [LogoutController::class, 'logout'])-&amp;gt;middleware(['auth:sanctum']);
});





&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;8) add auth table in Migrations folder module&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanxuxkg4cah3n3ysmxc9.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fanxuxkg4cah3n3ysmxc9.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;9)  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;php artisan migrate&lt;/li&gt;
&lt;li&gt;php artisan key:generate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;10) Move the User model to the Auth module's model directory&lt;br&gt;
&lt;code&gt;mv app/Models/User.php Modules/Auth/Models/User.php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;11)Update the namespace of the User model. Open Modules/Auth/Models/User.php and modify the namespace to:&lt;/p&gt;

&lt;p&gt;12) Update the config/auth.php file to use the Auth module's User model. In the config/auth.php file, locate the 'providers' configuration and modify it as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

 'providers' =&amp;gt; [
        'users' =&amp;gt; [
            'driver' =&amp;gt; 'eloquent',
            'model' =&amp;gt; Modules\Auth\Models\User::class,
        ],


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;13) Open the RegisterController and add the code below in it to create the method to register a user:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

use Illuminate\Support\Facades\Hash;

class RegisterController extends Controller
{

    public function register(Request $request)
    {
        $validatedData = $request-&amp;gt;validate([
            'name' =&amp;gt; 'required|string|max:255',
            'email' =&amp;gt; 'required|string|email|max:255|unique:users',
            'password' =&amp;gt; 'required|string|min:8',
        ]);

        $user = User::create([
            'name' =&amp;gt; $validatedData['name'],
            'email' =&amp;gt; $validatedData['email'],
            'password' =&amp;gt; Hash::make($validatedData['password']),
        ]);

        $token = $user-&amp;gt;createToken('auth_token')-&amp;gt;plainTextToken;

        return response()-&amp;gt;json([
            'access_token' =&amp;gt; $token,
            'token_type' =&amp;gt; 'Bearer',
        ]);
    }
}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;First, we validate the incoming request to make sure all required variables are present. Once a user has been created, we create a new personal access token  using the createToken() method and give the token a name of auth_token, we call the plainTextToken on the instance to access the plain-text value of the token. Finally, we return a JSON response containing the generated token as well as the type of the token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgv59j3re41kg23g9nmxj.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgv59j3re41kg23g9nmxj.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;14) Then add the login() method inside of the LoginController:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

use Illuminate\Support\Facades\Auth;

class LoginController extends Controller
{

    public function login(Request $request)
    {
        if (!Auth::attempt($request-&amp;gt;only('email', 'password'))) {
            return response()-&amp;gt;json([
                'message' =&amp;gt; 'Invalid login details'
            ], 401);
        }

        $user = User::where('email', $request['email'])-&amp;gt;firstOrFail();
        $token = $user-&amp;gt;createToken('auth_token')-&amp;gt;plainTextToken;

        return response()-&amp;gt;json([
            'user'         =&amp;gt; $user,
            'access_token' =&amp;gt; $token,
            'token_type'   =&amp;gt; 'Bearer',
        ]);
    }
}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnll92fbee2d6v8teqexi.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnll92fbee2d6v8teqexi.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;15) forgot password &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; make mail &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;php artisan module:make-mail ResetPassword Auth&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?php

namespace Modules\Auth\App\Emails;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class ResetPassword extends Mailable
{
    use Queueable, SerializesModels;

    public $data;

    public function __construct($data)
    {
        $this-&amp;gt;data = $data;
    }

    public function build()
    {
        return $this-&amp;gt;subject('Mail from ashrakt')-&amp;gt;view("auth::mails.resetPassword");
    }
}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt; make view&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;

&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Authentication&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
    &amp;lt;h3&amp;gt;code : {{ $data }}&amp;lt;/h3&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Forgot Password Controller&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?php

namespace Modules\Auth\App\Http\Controllers;

use Carbon\Carbon;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Modules\Auth\Models\User;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Modules\Auth\App\Emails\ResetPassword;


class ForgotPasswordController extends Controller
{

    public function sendResetLinkEmail(Request $request)
    {
        $request-&amp;gt;validate([
            'email' =&amp;gt; 'required|email|exists:users',
        ]);

        $token = Str::random(64);
        DB::table('password_reset_tokens')-&amp;gt;insert([
            'email' =&amp;gt; $request-&amp;gt;email,
            'token' =&amp;gt; $token,
            'created_at' =&amp;gt; Carbon::now()
        ]);

        Mail::to($request-&amp;gt;email)-&amp;gt;send(new ResetPassword($token));


        return response()-&amp;gt;json(['message' =&amp;gt; 'We have e-mailed your password reset link!']);
    }



    public function submitResetPasswordForm(Request $request)
    {
        $request-&amp;gt;validate([
            'email' =&amp;gt; 'required|email|exists:users',
            'token' =&amp;gt; 'required',
            'password' =&amp;gt; 'required|string|min:6|confirmed',
            'password_confirmation' =&amp;gt; 'required'
        ]);

        $updatePassword = DB::table('password_reset_tokens')
            -&amp;gt;where([
                'email' =&amp;gt; $request-&amp;gt;email,
                'token' =&amp;gt; $request-&amp;gt;token
            ])-&amp;gt;first();

        if (!$updatePassword) {
            return response()-&amp;gt;json(['message' =&amp;gt; 'Invalid token!']);
        }

        User::where('email', $request-&amp;gt;email)
            -&amp;gt;update(['password' =&amp;gt; Hash::make($request-&amp;gt;password)]);


        DB::table('password_reset_tokens')-&amp;gt;where(['email' =&amp;gt; $request-&amp;gt;email])-&amp;gt;delete();

        return response()-&amp;gt;json(['message' =&amp;gt; 'Your password has been changed!']);
    }
}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2ys0jnmfj1o9hmico3n.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2ys0jnmfj1o9hmico3n.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqg95cm7fcyxoc0wka2wf.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqg95cm7fcyxoc0wka2wf.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;env file&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=465
MAIL_USERNAME=####
MAIL_PASSWORD=####
MAIL_ENCRYPTION=tls
MAIL_MAILER=smtp
MAIL_FROM_ADDRESS=####
MAIL_FROM_NAME="${APP_NAME}"


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;16) Reset password&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?php

namespace Modules\Auth\App\Http\Controllers;

use Illuminate\Http\Request;
use Modules\Auth\Models\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;


class ResetPasswordController extends Controller
{

    public function resetPassword(Request $request)
    {
        $request-&amp;gt;validate([
            'email' =&amp;gt; 'required|email|exists:users',
            'password' =&amp;gt; 'required|string|min:6|confirmed',
            'password_confirmation' =&amp;gt; 'required'
        ]);

        User::where('email', $request-&amp;gt;email)
            -&amp;gt;update(['password' =&amp;gt; Hash::make($request-&amp;gt;password)]);

        return response()-&amp;gt;json(['message' =&amp;gt; 'Your password has been changed!']);
    }
}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgx3119acfi7yvcs8pn9.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgx3119acfi7yvcs8pn9.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;17) logout &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&amp;lt;?php

namespace Modules\Auth\App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Laravel\Sanctum\PersonalAccessToken;

class LogoutController extends Controller
{

    public function logout(Request $request)
    {
        $logout = PersonalAccessToken::findToken($request-&amp;gt;bearerToken())-&amp;gt;delete();

        if ($logout) {
            return response()-&amp;gt;json([
                'message' =&amp;gt; 'Successfully logged out.',
            ]);
        } else {
            return response()-&amp;gt;json([
                'message' =&amp;gt; 'Error occurred while logging out.',
            ]);
        }
    }
}



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqn4q31bxczma0e1fp0f.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsqn4q31bxczma0e1fp0f.PNG" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
