XWMS Docs xwms.nl
On this page Quick Setup 1) Install the package 2) Publish the config 3) Add env values 4) Add routes The correct flow (XWMS) Response format (always JSON) sign-token response (start auth) sign-token-verify response (user data) Required DB table Updated controller (uses new helper features) More usage patterns (copy/paste) 1) Manual login (no auto Auth::login) 2) Custom field mapping 3) Extra payload for token verification 4) Sync logged-in user later Sync a logged-in user Why `sub` matters Troubleshooting Summary

Laravel Installation

Laravel Installation - XWMS Authentication

This guide is the current Laravel setup for XWMS authentication. It uses the real XWMS flow: sign-token -> redirect -> sign-token-verify.

Important rule: link users by the stable sub id, not by email.


Quick Setup

1) Install the package

composer require xwms/package

2) Publish the config

php artisan vendor:publish --tag=xwms-config

3) Add env values

XWMS_CLIENT_ID=your_client_id_here
XWMS_CLIENT_SECRET=your_client_secret_here
XWMS_DOMAIN=your-domain.example
XWMS_REDIRECT_URI=http://your-app.test/xwms/validateToken
XWMS_API_URI=https://xwms.nl/api/

4) Add routes

use Illuminate\Support\Facades\Route;
use XWMS\Package\Controllers\Api\XwmsApiHelper;
use App\Http\Controllers\HomeController;

Route::get('/xwms/info', [XwmsApiHelper::class, 'info']);
Route::get('/xwms/auth', [XwmsApiHelper::class, 'auth']);
Route::get('/xwms/validateToken', [HomeController::class, 'authValidate']);

The correct flow (XWMS)

  1. Your app calls sign-token and gets a redirect URL.
  2. The user logs in on XWMS.
  3. XWMS redirects back with a token.
  4. Your server verifies the token using sign-token-verify.
  5. XWMS returns user data including sub (stable id).
  6. You link that sub to your local user (xwms_connections table).

This is not the Google OAuth code exchange. XWMS returns a token directly.


Response format (always JSON)

All XWMS responses use the same envelope:

{
  "status": "success",
  "message": "Human readable message",
  "data": { "..." : "payload" }
}
  • status is success or error
  • message explains what happened
  • data contains the payload for that endpoint

sign-token response (start auth)

When you call sign-token, XWMS responds with:

  • client_id (string)
  • token (string)
  • email (string, if available)
  • expires_at (ISO 8601 string)
  • url (string, the login/redirect URL)

The helper handles the redirect URL for you.


sign-token-verify response (user data)

When you verify the token, XWMS returns user data in data:

  • sub (string, stable user id)
  • name (string)
  • given_name (string)
  • family_name (string or null)
  • email (string)
  • email_verified (boolean)
  • picture (string URL)

Always link users by sub.


Required DB table

Create a connection table:

php artisan make:model XwmsConnection -m

Migration example:

Schema::create('xwms_connections', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('user_id')->index();
    $table->string('sub')->unique();
    $table->timestamps();
});

Updated controller (uses new helper features)

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use App\Models\User;
use App\Models\XwmsConnection;
use XWMS\Package\Controllers\Api\XwmsApiHelper;

class HomeController extends Controller
{
    public function authValidate()
    {
        $result = XwmsApiHelper::authenticateAndSyncUser([
            'login' => true,
            'remember' => true,
            'create_user' => true,
            'update_existing' => true,
            'link_by_email' => true,
            'image_sync' => [
                'enabled' => true,
                'disk' => 'public',
                'directory' => 'users/xwms',
                'delete_old' => true,
            ],
        ]);

        if (($result['status'] ?? null) !== 'success') {
            return redirect()->route('auth.login');
        }

        return redirect()->route('home.index');
    }
}

This uses the built-in helper to:

  • verify the token
  • read sub
  • find or create the user
  • update user data from XWMS
  • store the connection in xwms_connections

More usage patterns (copy/paste)

1) Manual login (no auto Auth::login)

$result = XwmsApiHelper::authenticateAndSyncUser([
    'login' => false,
    'remember' => false,
]);

if (($result['status'] ?? null) === 'success') {
    // Your own session logic here
}

2) Custom field mapping

XwmsApiHelper::authenticateAndSyncUser([
    'field_map' => [
        'name' => 'name',
        'email' => 'email',
        'img' => 'picture',
    ],
    'field_transforms' => [
        'name' => function ($value) {
            return trim($value ?? '');
        },
    ],
]);

3) Extra payload for token verification

XwmsApiHelper::authenticateAndSyncUser([
    'auth_payload' => [
        'extra' => 'value'
    ]
]);

4) Sync logged-in user later

$result = XwmsApiHelper::syncAuthenticatedUserFromXwms([
    'image_sync' => [
        'enabled' => true,
        'disk' => 'public',
        'directory' => 'users/xwms',
        'delete_old' => true,
    ],
]);

Sync a logged-in user

use XWMS\Package\Controllers\Api\XwmsApiHelper;

public function syncAccount()
{
    $result = XwmsApiHelper::syncAuthenticatedUserFromXwms();

    if (($result['status'] ?? null) !== 'success') {
        return back()->withErrors('Sync failed');
    }

    return back()->with('success', 'Account synced');
}

Why sub matters

Emails change. The sub never changes. Always link XWMS users by sub using the connection table.


Troubleshooting

  • Check that XWMS_REDIRECT_URI matches your route exactly.
  • Tokens are single use; try again after a failed attempt.
  • Do not log client secrets or tokens.

Summary

  • Use XwmsApiHelper::auth() to redirect to XWMS.
  • Use XwmsApiHelper::authenticateAndSyncUser() to validate and link users.
  • Use XwmsApiHelper::syncAuthenticatedUserFromXwms() to refresh profile data.
  • Always link by sub.