Overview of Mobile Auth Architecture Building authentication for mobile applications using NativePHP requires a shift in how we handle state. Unlike a standard web application where the backend and frontend often share the same environment, a mobile app acts as a client to a remote API. This tutorial demonstrates how to bridge that gap by implementing traditional email/password login and Google Socialite integration. The goal is to secure your mobile application while ensuring a smooth user experience, even during intermittent connectivity. Prerequisites and Essential Tools Before diving into the code, ensure you have a solid grasp of Laravel and Livewire. You will need two distinct environments: * **Mobile Repository:** The NativePHP codebase that compiles into an APK or IPA. * **API Repository:** A separate Laravel backend (ideally hosted via Laravel Forge) to handle database persistence and authentication logic via Laravel Sanctum. Registration and Token Retrieval The registration process begins with a Livewire component. We capture user data and a unique device identifier using the NativePHP Device plugin. This ID allows the backend to track which specific device owns the session. ```php // NativePHP Livewire Component public function register() { $device = Device::info(); $response = Http::post('https://api.yourdomain.com/v1/auth/register', [ 'name' => $this->name, 'email' => $this->email, 'password' => $this->password, 'device_name' => $device['model'], ]); if ($response->successful()) { session(['token' => $response->json('token')]); return redirect()->route('home'); } } ``` On the backend, Laravel Sanctum generates a plain-text token upon successful validation. This token becomes the "key" for all subsequent requests. Managing Tokens and Offline Logic Security in mobile apps involves more than just checking if a token exists. You must verify it against the server periodically. However, mobile users often lose signal. A robust middleware should handle both verification intervals (e.g., every 15 minutes) and a "grace period" for offline access. ```php // Middleware Logic $lastVerified = session('token_verified_at'); if (now()->diffInMinutes($lastVerified) > 15) { try { $this->verifyTokenRemotely($token); } catch (ConnectionException $e) { // Allow offline access if verified within the last 24 hours if (now()->diffInHours($lastVerified) > 24) { return redirect()->route('login'); } } } ``` Social Auth with Deep Linking To implement Google sign-in, we use Laravel Socialite on the API side. The mobile app opens a browser instance to handle the OAuth flow. Once finished, the API redirects the user back to the app using a **Deep Link Scheme** (e.g., `nativephp://callback`). You must define this scheme in your `.env` file to ensure the mobile OS knows to hand the data back to your application. Storage Best Practices While using the PHP `session()` is functional for demos, it is not the most secure method. NativePHP offers a **Mobile Secure Storage** plugin. This paid add-on uses hardware-level encryption on the device to store tokens, ensuring they survive app reloads and provide a higher security tier than standard session files.
Laravel Sanctum
Products
- Mar 26, 2026
- Jan 31, 2026
- Jan 20, 2026
- Dec 11, 2025
- Dec 7, 2025
Overview Integrating Next.js with Laravel provides a potent combination of a high-performance React frontend and a robust, feature-rich PHP backend. While Inertia.js offers a seamless full-stack experience, many developers prefer a decoupled architecture where Laravel serves strictly as an API layer. This approach allows for incremental adoption of Laravel's features—like queues, mailables, and advanced authentication—into an existing frontend without migrating the entire codebase at once. Prerequisites To follow along, you should have a solid grasp of **JavaScript (ES6+)** and **PHP**. You will need Node.js and Composer installed locally to manage dependencies for both frameworks. Familiarity with React hooks and RESTful API concepts is essential. Key Libraries & Tools - **Laravel Sanctum**: Provides a featherweight authentication system for SPAs and mobile applications. - **Next.js 15**: The React framework for production, utilizing Server Components for optimized data fetching. - **HTTPie**: A user-friendly command-line HTTP client for testing API endpoints. Code Walkthrough 1. Setting up the Laravel API Initialize a new Laravel project and install the API scaffolding to prepare the backend for external requests. ```bash laravel new api php artisan install:api ``` This command configures Laravel Sanctum and creates the `api.php` routes file. Define a simple test route in `routes/api.php`: ```php Route::get('/hi', function () { return response()->json([ 'message' => 'Hello from Laravel', 'description' => 'Your API is live!' ]); }); ``` 2. Fetching Data in Next.js In Next.js 15, fetch data directly within a **Server Component**. This keeps sensitive logic off the client and improves performance. ```javascript export default async function Page() { const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/api/hi`); const data = await res.json(); return ( <div> <h1>{data.message}</h1> <p>{data.description}</p> </div> ); } ``` 3. Implementing Sanctum Token Auth For authorized requests, use Sanctum to issue tokens. On the Next.js side, once you receive a token from a login endpoint, store it as a secure cookie. Include this token in the `Authorization` header for subsequent requests: ```javascript const response = await fetch('/api/bookmarks', { headers: { 'Authorization': `Bearer ${token}`, 'Accept': 'application/json', }, }); ``` Syntax Notes Laravel uses **Arrow Functions** in routes for brevity and **Resource Classes** to transform JSON responses. Next.js 15 emphasizes **Async/Await** within components, moving away from `useEffect` for initial data loads. Always use `process.env` for API URLs to ensure environment consistency. Practical Examples You can use this setup to offload heavy processing. For instance, a Next.js frontend can trigger a **Laravel Queue** via an API call to process video uploads or generate complex reports in the background without blocking the UI. Tips & Gotchas - **CORS Issues**: Ensure your `config/cors.php` in Laravel allows the origin where your Next.js app is hosted. - **Cache Management**: Next.js 15 caches fetch requests by default. If your data changes frequently, use `revalidate` or `no-store` options. - **Domain Matching**: If using Sanctum's cookie-based auth instead of tokens, the frontend and backend must share the same top-level domain.
May 8, 2025Overview of the Jetstream Ecosystem Laravel Jetstream represents the sophisticated evolution of application scaffolding. While Laravel Breeze offers a minimal entry point, Jetstream provides a robust foundation for complex projects requiring professional-grade features out of the box. It manages the heavy lifting of authentication, team management, and API infrastructure so you can focus on core business logic. Prerequisites and Installation To get started, you should be comfortable with the PHP ecosystem and the basic Laravel directory structure. You can initiate a project using the Laravel installer by selecting Jetstream as your starter kit. During installation, you must choose between two frontend stacks: Livewire with Blade or Inertia.js with Vue.js. Key Libraries & Tools - **Laravel Sanctum**: Powers the API token system, allowing users to issue scoped permissions for third-party integrations. - **Livewire**: A framework for building reactive interfaces using only PHP. - **Inertia.js**: Bridges the gap between server-side routing and modern single-page applications. - **Tailwind CSS**: Handles the utility-first styling for the entire dashboard and profile views. Customizing the Logic with Action Classes Jetstream utilizes "Action" classes to handle core logic, found in `app/Actions/Jetstream`. This pattern keeps your controllers clean and your logic reusable. ```php // Example: Configuring permissions in JetstreamServiceProvider Jetstream::role('admin', 'Admin', [ 'create', 'read', 'update', 'delete', ])->description('Administrator users can perform any action.'); ``` You can modify these classes to inject custom validation or business rules directly into the user registration or team creation flows. For UI changes, navigate to `resources/views` (for Livewire) to edit the dashboard components or the welcome screen. Syntax Notes & Best Practices Jetstream leans heavily on **Service Providers** for configuration. Use the `JetstreamServiceProvider` to define user roles and granular permissions. One notable pattern is the use of the `features` array in `config/jetstream.php`. Toggling a boolean here can instantly enable Two-Factor Authentication (2FA) or profile photo uploads across your entire app. Tips & Gotchas Avoid treating Jetstream as a package you periodically update. Once installed, the code lives in your application's `app` and `resources` directories. It belongs to you. If you need to change the behavior of the registration process, modify the `CreateNewUser` action directly rather than trying to extend it. Always remember to run your migrations after enabling team support, as it requires specific database tables to track memberships.
Jul 18, 2024Overview: Refined Authentication and Filtering In this technical exploration, we tackle the architectural complexities of building a high-performance reservation system within the Laravel ecosystem. The primary objective involves streamlining the user experience for an office-rental platform—similar to Airbnb—where both tenants and hosts require granular control over their reservation data. We address critical authentication hurdles using Laravel Sanctum, optimize database interactions via lazy loading traits, and implement complex query grouping to ensure data integrity during date-range filtering. Mastering these patterns is essential for any developer building multi-tenant or marketplace applications. Authentication isn't just about logging in; it’s about ensuring that public endpoints can still identify users when a token is present. Similarly, filtering isn't just about `WHERE` clauses; it's about managing logical groupings in SQL to prevent data leakage between users. This guide breaks down the "why" behind these advanced patterns, moving beyond basic CRUD into professional-grade backend engineering. Prerequisites To follow this guide, you should have a solid grasp of the following: * **PHP 8.x**: Familiarity with closures and arrow functions. * **Laravel Framework**: Understanding of Controllers, Eloquent models, and the Service Container. * **RESTful API Design**: Knowledge of headers, query parameters, and JSON response structures. * **Testing Basics**: Experience with PHPUnit or Laravel's built-in testing suite. Key Libraries & Tools * **Laravel Sanctum**: Provides a featherweight authentication system for SPAs and mobile apps using API tokens. * **LazilyRefreshDatabase**: A newer Laravel trait that optimizes test performance by only running migrations when a database connection is actually requested. * **Composer**: The dependency manager for PHP, used here to ensure the framework is updated to leverage the latest `assertNotSoftDeleted` assertions. Solving the Sanctum Default Guard Dilemma A common friction point in Laravel APIs occurs when an endpoint is accessible to both guests and authenticated users. By default, Laravel uses the `web` (session) guard. If you are building a stateless API with Laravel Sanctum, your application will fail to identify the user even if a valid `Authorization` bearer token is sent, because it isn't looking for one. The Guard Switch To fix this globally, we update `config/auth.php` to set the default guard to `sanctum`. This ensures that even on routes not protected by the `auth:sanctum` middleware, the `auth()->user()` helper will correctly attempt to resolve the user from the token. However, this change has a ripple effect on your test suite. Standard testing helpers like `$this->actingAs($user)` default to the session guard, leading to `401 Unauthorized` errors in your tests because the application is now expecting a Sanctum token. Overriding actingAs in TestCase Instead of manually updating every test to use `Sanctum::actingAs()`, a cleaner approach involves overriding the method in your base `TestCase.php`. This maintains a clean API for your tests while ensuring the underlying logic matches your production authentication guard. ```python // Base TestCase.php public function actingAs(UserContract $user, $guard = null) { return Sanctum::actingAs($user, ['*']); } ``` This methodical override allows you to keep your test syntax succinct while bridging the gap between session-based testing and token-based production environments. Implementing Logical Query Grouping When filtering reservations by date ranges, developers often run into a logic bug where an `OR` condition breaks the security of the `user_id` constraint. If you write a query that looks for `user_id = 1` AND `start_date` is X OR `end_date` is Y, the `OR` might return records belonging to other users if they match the date condition. The Closure Fix To prevent this, we encapsulate the date logic inside a PHP closure. This forces Laravel to wrap those specific conditions in parentheses in the generated SQL. ```python $reservations = Reservation::query() ->where('user_id', auth()->id()) ->where(function ($query) use ($request) { $query->whereBetween('start_date', [$request->from_date, $request->to_date]) ->orWhereBetween('end_date', [$request->from_date, $request->to_date]); }) ->get(); ``` By grouping the `whereBetween` and `orWhereBetween` calls, we ensure the query remains restricted to the authenticated user's data regardless of how many date conditions we add. This is a non-negotiable best practice for data privacy. Advanced Filtering for Hosts While tenants filter by their own ID, hosts need to filter reservations across multiple offices they own. We use the `whereRelation` method for a clean, readable syntax that checks the owner of the office associated with a reservation. This avoids manual joins and keeps the code expressive. ```python $reservations = Reservation::query() ->whereRelation('office', 'user_id', auth()->id()) ->when($request->office_id, fn($q) => $q->where('office_id', $request->office_id)) ->when($request->status, fn($q) => $q->where('status', $request->status)) ->get(); ``` Syntax Notes: Modern Laravel Conventions Several modern conventions were utilized to keep the codebase lean: 1. **LazilyRefreshDatabase**: This trait is a performance booster. In a large test suite, skipping migrations for tests that only check basic logic (like validation) saves significant time. 2. **AssertNotSoftDeleted**: Instead of manually checking the database for a null `deleted_at` timestamp, this dedicated assertion provides a more semantic way to verify that a resource was not removed. 3. **HTTP Build Query**: When testing, using `http_build_query($params)` is a robust way to generate URL strings for GET requests, ensuring special characters are properly encoded. Practical Examples Consider a user searching for their past bookings to prepare for an expense report. They need to filter by a specific date range. Without the logical grouping discussed, the system might accidentally show them other people's bookings that occurred in the same month—a massive security breach. By implementing the closure-based grouping, the `user_id` check acts as a global filter that cannot be bypassed by the `OR` logic of the date search. Another example is the Host Dashboard. A host managing 10 different offices needs to see only the "Active" reservations for a specific "Downtown Loft." By using the `when()` helper in Eloquent, we build a dynamic query that only applies filters if the user provides them, keeping the API flexible and the controller clean. Tips & Gotchas * **The Validation Trap**: Don't skip validation just because a query might return empty results. Validating that a `to_date` is after a `from_date` prevents the SQL engine from processing nonsensical ranges and provides better feedback to the frontend. * **Query Performance**: If you are filtering by geographical location (e.g., nearest office), avoid using `SQRT` functions in your SQL if possible. Using squared distances for comparisons is significantly faster and achieves the same sorting result. * **Middleware Clarity**: Just because you set Sanctum as the default guard doesn't mean your routes are protected. You still need the `auth:sanctum` middleware for any endpoint that should be strictly private.
Sep 30, 2021Overview: The Strategic Blueprint for Modern Laravel APIs Building a Laravel application requires more than just running a few terminal commands; it demands a clear understanding of the 'why' behind architectural choices. When starting a project from scratch—like the office-rental platform for remote workers we are building—the initial setup phase is the most critical. This is where you define the relationships between your data, establish your coding conventions, and set the stage for a scalable, maintainable codebase. Developing with an **API-first** mindset means prioritizing the backend's ability to serve data consistently to any client, whether it is a Single Page Application (SPA), a mobile app, or a traditional Blade frontend. By decoupling the logic from the presentation layer early on, you ensure that your application remains flexible as it grows. This tutorial focuses on the foundational "spike and stabilize" workflow: writing functional code quickly to prove a concept, then reinforcing it with robust tests and Eloquent refinements. Prerequisites: Essential Tools and Concepts To follow this guide, you should be comfortable with the following: * **PHP 8.x**: Knowledge of modern PHP features like constructor property promotion and attributes. * **Laravel Framework**: Familiarity with the MVC pattern and Artisan CLI. * **Relational Databases**: Understanding of foreign keys and many-to-many relationships. * **Composer**: Ability to manage PHP dependencies. * **Testing Basics**: Basic understanding of PHPUnit or Laravel's built-in testing suite. Key Libraries & Tools * Laravel Framework: The primary PHP framework used for the backend. * Eloquent ORM: Laravel's database abstraction layer for managing models and relationships. * Laravel Sanctum: A lightweight authentication system for APIs and SPAs. * PHPUnit: The testing framework used to validate our API endpoints. * Faker: A PHP library used within factories to generate realistic dummy data. Code Walkthrough: Database Migrations and Model Relationships Our database schema must support a variety of features, including office listings, tags for amenities, and polymorphic images. Let's start with the polymorphic image relationship, which allows us to attach images to any model (offices, reviews, or users) without creating separate tables for each. 1. Defining the Polymorphic Image Migration ```php Schema::create("images", function (Blueprint $table) { $table->id(); $table->string("path"); $table->numericMorphs("imageable"); $table->timestamps(); }); ``` The `numericMorphs` method is a powerful shortcut. It creates both `imageable_id` (a big integer) and `imageable_type` (a string) columns while automatically indexing them. This enables the **MorphMany** relationship in our models. 2. Establishing Model Relationships and Casts Inside the `Office` model, we define how it interacts with users, reservations, and images. We also use **Attribute Casting** to ensure that data retrieved from the database is in the correct format for our logic. ```php class Office extends Model { use SoftDeletes; protected $casts = [ "lat" => "decimal:8", "lng" => "decimal:8", "approval_status" => "integer", "hidden" => "boolean", "price_per_day" => "integer", ]; public function user(): BelongsTo { return $this->belongsTo(User::class); } public function images(): MorphMany { return $this->morphMany(Image::class, "resource"); } } ``` Notice the use of `decimal:8` in the casts. This ensures that coordinate data for maps maintains its precision. We also utilize constants for statuses rather than magic numbers to make the code readable and self-documenting. Syntax Notes: Mass Assignment and Immutable Dates A common point of friction in Laravel is **Mass Assignment Protection**. While it serves as a security layer to prevent users from injecting unexpected data into your database, it can be cumbersome during rapid development. In this project, we disable it globally in the `AppServiceProvider` because we strictly validate all incoming request data before it ever hits the model. ```php // In AppServiceProvider.php public function boot() { Model::unguard(); } ``` Another modern best practice is using **Immutable Dates**. When working with reservation ranges, a mutable date object can lead to bugs where modifying the 'end date' accidentally changes the 'start date' because they share the same object reference. By casting to `immutable_date`, any modification creates a new instance, leaving the original untouched. ```php protected $casts = [ "start_date" => "immutable_date", "end_date" => "immutable_date", ]; ``` Practical Examples: Building the API Resources Instead of returning raw Eloquent models, we use **API Resources**. These act as a transformation layer between your database and your JSON output. This is vital for maintaining a stable API contract; if you rename a database column, you only need to update the resource mapping, and your frontend won't break. The Tag Controller Implementation For simple resources like tags (amenities like "Air Conditioning" or "Private Bathroom"), an **invokable controller** is often the cleanest approach. It focuses the class on a single action. ```php class TagController extends Controller { public function __invoke() { return TagResource::collection(Tag::all()); } } ``` This keeps our `api.php` routes file lean and emphasizes the specific responsibility of the controller. Tips & Gotchas: The Spike and Stabilize Method 1. **Don't Let Enums Block You**: While PHP now supports native Enums, using them in database migrations can be risky. Altering an ENUM column in a large database often requires locking the table, which causes downtime. Using integer constants in your model provides the same readability without the database-level headaches. 2. **Factory Count Shortcuts**: When writing tests, you can quickly generate multiple models using `Office::factory()->count(3)->create()`. This is essential for testing pagination and sorting logic. 3. **The 'Latest' Helper**: Laravel provides a `latest()` query scope that defaults to `created_at`. However, if you want to sort by ID for performance or specific ordering, you can pass the column name: `Office::query()->latest("id")->get()`. 4. **Testing JSON Structure**: When asserting API responses, avoid checking the exact JSON string. Instead, use `assertJsonCount()` or `assertJsonPath()`. This makes your tests **future-proof**—they won't break just because you added a new field to the resource later on.
Sep 10, 2021The Persistence Problem Standard session-based authentication protects users through brevity. By default, Laravel expires session cookies after two hours of inactivity. This prevents a forgotten browser tab from becoming a permanent gateway to private data. However, modern user experience often demands persistence. We solve this by implementing the "Remember Me" pattern and transitioning to token-based security for decoupled environments. Implementing Remember Me Laravel simplifies long-term sessions via the `attempt` method. By passing a boolean as the second argument, you instruct the framework to issue a "recalling" cookie that outlives the standard session. ```php public function login(Request $request) { $credentials = $request->only('email', 'password'); $remember = $request->filled('remember'); if (Auth::attempt($credentials, $remember)) { return redirect()->intended('dashboard'); } } ``` Under the hood, Laravel generates a unique string, stores a hashed version in your `users` table's `remember_token` column, and sends an encrypted cookie to the browser. If the session expires, the framework automatically re-authenticates the user using this token. Token-Based Auth with Sanctum Mobile apps and SPAs require a stateless approach. Laravel Sanctum serves as the industry standard here. It issues a plain-text token upon login that the client must store and include in every subsequent request header. To issue a token, verify the user's credentials manually using the `Hash::check` facade, then invoke `createToken` on the user model: ```php $user = User::where('email', $request->email)->first(); if ($user && Hash::check($request->password, $user->password)) { return ['token' => $user->createToken('api-token')->plainTextToken]; } ``` Guarding API Routes Protecting these endpoints requires the `auth:sanctum` middleware in your `api.php` file. This tells Laravel to ignore traditional sessions and instead look for a `Bearer` token in the `Authorization` header. When a user logs out, calling `$user->currentAccessToken()->delete()` instantly invalidates that specific token in the database, ensuring immediate revocation across all devices.
Aug 26, 2021Overview Authentication serves as the gatekeeper for your application, ensuring only identified users access private data or perform sensitive actions. In Laravel, session-based authentication provides a seamless, secure way to manage state across requests. It works by generating a unique session ID stored in a browser cookie, which the server maps to a specific user record in the database. This method is highly recommended for traditional HTML front-ends where security and ease of implementation are paramount. Prerequisites To follow this guide, you should have a baseline understanding of PHP and the Laravel framework. You should be familiar with MVC patterns, MySQL databases, and how to run basic terminal commands using Laravel Sail. Key Libraries & Tools * **Laravel**: The primary PHP framework providing built-in authentication services. * **Laravel Sail**: A Docker-powered CLI for running Laravel applications locally. * **Eloquent ORM**: Handles database interactions and user models. * **Laravel Sanctum**: Mentioned as the go-to package for future token-based API authentication. Code Walkthrough Database Setup and Seeding First, prepare your environment by migrating the user table and seeding it with test data. The database stores passwords as secure hashes, never plain text. ```bash sail artisan migrate --seed ``` Handling the Login Logic Inside your `AuthController`, use the `validator` helper to ensure the user provides a valid email and password. Once validated, call the `auth()->attempt()` method. This method compares the input against the database and automatically manages the session if they match. ```python if (auth()->attempt($request->only('email', 'password'))) { return redirect()->route('dashboard'); } return back()->withErrors(['email' => 'Invalid credentials']); ``` Protecting Routes with Middleware To block unauthenticated access to the dashboard, wrap your routes in the `auth` middleware. This ensures the controller logic never executes unless a valid session exists. ```python Route::get('/dashboard', [DashboardController::class, 'index']) ->middleware('auth'); Route::get('/', function () { return view('login'); })->name('login'); ``` Syntax Notes The `auth()` helper is a powerful shortcut that returns an instance of the `AuthFactory` contract. Additionally, the `withErrors()` method on redirects allows you to pass validation feedback back to the Blade view efficiently. Tips & Gotchas A common mistake is forgetting to name your login route. The `auth` middleware specifically looks for a route named `login` to redirect unauthorized users. If this name is missing, your application will throw an error rather than redirecting properly.
Aug 23, 2021Refining the Starter Kit Experience Laravel recently pushed Jetstream 2.0 to production, marking a significant shift in how the framework handles authentication views. The biggest change involves the Inertia.js stack. While the initial release utilized Blade for login and registration to avoid duplication, the community demanded a more unified Vue.js experience. Jetstream 2.0 delivers this by rewriting all authentication views as native Vue pages. Beyond the UI, team management received a vital upgrade: developers can now invite users who don't yet have an account via email, removing a major friction point in the user onboarding flow. Collaborative Infrastructure with Forge Circles For teams managing infrastructure, Laravel Forge introduced a long-awaited update to its Circle feature. Historically, only the circle owner could provision new hardware. The latest update allows members to create servers directly within a shared credential, such as DigitalOcean or AWS. This delegation of power transforms Forge Circles from a simple viewing gallery into a true collaborative tool for DevOps teams. The Evolution of Spark and Billing Laravel Spark is undergoing a total architectural pivot. To simplify the tool, non-billing features like API management and two-factor authentication were moved into Jetstream and open-sourced for free. The upcoming Spark release focuses exclusively on subscription billing. Taking inspiration from the Stripe billing portal, the new Spark operates as an isolated panel with its own assets. This decoupling means Spark no longer dictates your application's CSS or JavaScript choices; it ships its own Tailwind CSS and Vue files that remain separate from your main application layout. Future Considerations for React SPAs Taylor Otwell is currently weighing the release of a Next.js and React starter kit. This potential tool would offer a canonical example of a Single Page Application (SPA) authenticating with Laravel Sanctum. While the demand for such a template is high, the decision is complicated by previous community confusion regarding the necessity of starter kits. The goal remains providing a clear path for modern frontend integration without imposing rigid opinions on the core framework.
Jan 11, 2021