zhylon / zhylon-auth
Zhylon OAuth2 Provider for Laravel Socialite
Requires
- php: ^8.3|^8.4|8.5
- ext-json: *
- laravel/socialite: ^5.24
Requires (Dev)
- laravel/pint: ^1.27
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-17 13:45:02 UTC
README
Zhylon OAuth2 Provider for Laravel Socialite
Integrate ZhylonID single sign-on into your Laravel application with just a few lines of code. This package provides a first-class Laravel Socialite driver for the Zhylon OAuth2 service, handling the full authentication flow, token management, and user synchronization out of the box.
๐ Table of Contents
- Features
- Requirements
- Installation
- Configuration
- Preparing Your User Model
- Usage
- Environment Variables Reference
- Troubleshooting
- Testing
- Security
- Changelog
- Contributing
- Credits
- License
โจ Features
- Drop-in Laravel Socialite driver for Zhylon OAuth2
- Automatic user creation and synchronization on login
- Stores
zhylon_id,zhylon_token, andzhylon_refresh_tokenon your User model - Fully configurable routes (prefix, paths, middleware, names, controller)
- Optional "remember me" cookie โ always, never, or per request
- Configurable callback URL, guard, and post-login destination
- Ships with a ready-to-use migration for the required user fields
- Minimal setup โ works with any existing Laravel auth scaffold
๐ฆ Requirements
| Dependency | Version |
|---|---|
| PHP | ^8.3 |
| Laravel | ^10.0 | ^11.0 | ^12.0 | ^13.0 |
| Laravel Socialite | ^5.24 |
Note: You need an active ZhylonID account and a registered OAuth application. Sign up at https://id.zhylon.net.
๐ Installation
Install the package via Composer:
composer require zhylon/zhylon-auth
Publish the configuration file and migration:
php artisan vendor:publish --provider="Zhylon\ZhylonAuth\Providers\ZhylonAuthServiceProvider"
Run the database migration to add the required columns to your users table:
php artisan migrate
โ๏ธ Configuration
Environment Variables
Add the following variables to your .env file. You will find the client
credentials in your ZhylonID dashboard after
registering your application.
ZHYLON_AUTH_CLIENT_ID=your-client-id ZHYLON_AUTH_CLIENT_SECRET=your-client-secret ZHYLON_AUTH_CALLBACK_WEBSITE="https://your-application.com"
Optional settings โ these have sensible defaults but can be customized:
# The ZhylonID base URI (default: https://id.zhylon.net) ZHYLON_AUTH_BASE_URI="https://id.zhylon.net" # Where to redirect the user after a successful login (default: /dashboard) ZHYLON_AUTH_HOME="/dashboard" # Set the "remember me" cookie: true, false or request (default: false) ZHYLON_AUTH_REMEMBER=false
Routes
By default the package registers these routes:
| Name | URL |
|---|---|
zhylon-auth.redirect |
/auth/zhylon/redirect |
zhylon-auth.callback |
/auth/zhylon/callback |
Every part of the URL can be changed:
ZHYLON_AUTH_SITE_PATH="/sso" # prefix ZHYLON_AUTH_REDIRECT_PATH="/login" # -> /sso/login ZHYLON_AUTH_CALLBACK_PATH="/return" # -> /sso/return
Middleware, route name prefix and the controller class can be set in the
routes section of config/zhylon-auth.php. To register the routes yourself,
set ZHYLON_AUTH_ROUTES_ENABLED=false and keep the route names
(zhylon-auth.redirect / zhylon-auth.callback). The OAuth callback URL is
built from the callback route, so it always matches your configuration.
Link to the login with:
<a href="{{ route('zhylon-auth.redirect') }}">Login with Zhylon</a>
Remember Me
ZHYLON_AUTH_REMEMBER controls Laravel's "remember me" cookie:
| Value | Behavior |
|---|---|
false |
Never set the cookie (default) |
true |
Always set the cookie |
request |
Set it when the redirect route is called with ?remember=1 |
With request you can offer a "stay signed in" checkbox:
<form method="GET" action="{{ route('zhylon-auth.redirect') }}"> <label><input type="checkbox" name="remember" value="1"> Stay signed in</label> <button type="submit">Login with Zhylon</button> </form>
Your
userstable needs aremember_tokencolumn (included in Laravel's default migration).
Login Link Parameters
The redirect route accepts these optional query parameters:
| Parameter | Description |
|---|---|
intended |
Where to send the user after login, e.g. /settings |
login_hint |
E-mail address passed to ZhylonID to pre-fill the login form |
remember |
1 to set the "remember me" cookie (only with ZHYLON_AUTH_REMEMBER=request) |
route('zhylon-auth.redirect', [ 'intended' => '/settings', 'login_hint' => $email, 'remember' => 1, ]);
This is also the URL to use as return address for links sent by ZhylonID
(e.g. magic links): after the user is signed in at ZhylonID, the OAuth flow
runs without any further prompt and the user lands on intended.
intended only accepts paths of your application (/settings) or absolute
URLs on the current host. Anything else is ignored to prevent open redirects,
and the user is sent to ZHYLON_AUTH_HOME instead. Without intended, the
URL Laravel stored when a guest opened a protected page is used.
Config File
After publishing, the config file is available at config/zhylon-auth.php.
This file maps the environment variables above and can be adjusted for more
advanced setups (e.g., per-environment overrides).
๐ค Preparing Your User Model
The package syncs OAuth user data into your User model. You need to add the
three Zhylon fields to the $fillable array so that mass-assignment works
correctly:
// app/Models/User.php protected $fillable = [ 'name', 'email', // ... your existing fields ... 'zhylon_id', 'zhylon_token', 'zhylon_refresh_token', ];
The migration published in the previous step will automatically add these three columns to your users table:
| Column | Type | Description |
|---|---|---|
zhylon_id |
string|null |
Unique user ID from ZhylonID |
zhylon_token |
text|null |
Current OAuth access token |
zhylon_refresh_token |
text|null |
OAuth refresh token for re-authentication |
๐งโ๐ป Usage
OAuth Flow Overview
The package implements the standard OAuth2 Authorization Code flow:
User clicks "Login with Zhylon"
โ
โผ
Your app redirects โ https://id.zhylon.net/oauth/authorize
โ
โผ (User authenticates & grants permission)
โ
Zhylon redirects back โ https://your-app.com/auth/zhylon/callback
โ
โผ
Package exchanges code for token, creates/updates User, logs them in
โ
โผ
User is redirected to ZHYLON_AUTH_HOME
Controller Example
The package registers the redirect and callback routes automatically. If you need to build a custom controller or override the default behavior, here is a full example:
<?php namespace App\Http\Controllers\Auth; use App\Models\User; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Auth; use Laravel\Socialite\Facades\Socialite; class ZhylonAuthController extends Controller { /** * Redirect the user to the ZhylonID authorization page. */ public function redirect() { return Socialite::driver('zhylon') ->scopes(['profile.read']) ->redirect(); } /** * Handle the callback from ZhylonID after authorization. */ public function callback() { $socialiteUser = Socialite::driver('zhylon')->user(); $user = User::updateOrCreate( ['zhylon_id' => $socialiteUser->getId()], [ 'name' => $socialiteUser->getName(), 'email' => $socialiteUser->getEmail(), 'zhylon_token' => $socialiteUser->token, 'zhylon_refresh_token' => $socialiteUser->refreshToken, ] ); Auth::login($user, remember: true); return redirect()->intended(config('zhylon-auth.login.home', '/dashboard')); } }
Register the routes in routes/web.php:
use App\Http\Controllers\Auth\ZhylonAuthController; Route::get('/auth/zhylon', [ZhylonAuthController::class, 'redirect'])->name('auth.zhylon'); Route::get('/auth/zhylon/callback', [ZhylonAuthController::class, 'callback'])->name('auth.zhylon.callback');
Accessing User Data
Once the user is authenticated, you can access the Zhylon-specific fields directly from the authenticated user:
$user = Auth::user(); echo $user->zhylon_id; // Zhylon user identifier echo $user->zhylon_token; // Current access token echo $user->zhylon_refresh_token; // Refresh token
Token Refresh
If you need to refresh an expired access token on behalf of a user, you can
use Socialite's refreshToken method:
use Laravel\Socialite\Facades\Socialite; $newToken = Socialite::driver('zhylon') ->refreshToken($user->zhylon_refresh_token); $user->update([ 'zhylon_token' => $newToken->token, 'zhylon_refresh_token' => $newToken->refreshToken, ]);
Note: ZhylonID may rotate refresh tokens on use. Always persist the new refresh token returned from this call.
๐ Environment Variables Reference
| Variable | Required | Default | Description |
|---|---|---|---|
ZHYLON_AUTH_CLIENT_ID |
โ | โ | Your OAuth application's client ID |
ZHYLON_AUTH_CLIENT_SECRET |
โ | โ | Your OAuth application's client secret |
ZHYLON_AUTH_CALLBACK_WEBSITE |
โ | config('app.url') |
Base URL of your application (no trailing slash) |
ZHYLON_AUTH_BASE_URI |
โ | https://id.zhylon.net |
ZhylonID OAuth server base URL |
ZHYLON_AUTH_ROUTES_ENABLED |
โ | true |
Register the package routes |
ZHYLON_AUTH_SITE_PATH |
โ | /auth/zhylon |
Route prefix |
ZHYLON_AUTH_REDIRECT_PATH |
โ | /redirect |
Path of the redirect route (after the prefix) |
ZHYLON_AUTH_CALLBACK_PATH |
โ | /callback |
Path of the callback route (after the prefix) |
ZHYLON_AUTH_REMEMBER |
โ | false |
"Remember me" cookie: true, false, request |
ZHYLON_AUTH_GUARD |
โ | default guard | Auth guard used for the login |
ZHYLON_AUTH_HOME |
โ | /dashboard |
Redirect destination after successful login |
ZHYLON_AUTH_LOGIN_URL |
โ | /login |
Redirect destination when the login fails |
ZHYLON_AUTH_USER_MODEL |
โ | auth.providers.users.model |
User model class |
ZHYLON_AUTH_CREATE_TEAM |
โ | true |
Create a Jetstream personal team on first login |
ZHYLON_AUTH_RANDOM_PASSWORD |
โ | true |
Set a random password for new users |
๐ง Troubleshooting
InvalidStateException after callback
This typically happens when the session is lost between the redirect and the
callback. Make sure your session middleware is applied to the callback
route and that your session driver is properly configured.
Client error: 401 Unauthorized
Double-check that ZHYLON_AUTH_CLIENT_ID and ZHYLON_AUTH_CLIENT_SECRET in
your .env match the credentials in your ZhylonID dashboard.
Also clear the config cache: php artisan config:clear.
Callback URL mismatch
The callback URL registered in your ZhylonID application must exactly match the
value of ZHYLON_AUTH_CALLBACK_WEBSITE + ZHYLON_AUTH_SITE_PATH + ZHYLON_AUTH_CALLBACK_PATH.
For example: https://your-app.com/auth/zhylon/callback.
Run php artisan route:list --name=zhylon-auth to see the registered URLs.
Columns not found after migration
If the migration did not run, execute php artisan migrate. If the columns
are missing from the migration file, re-publish with:
php artisan vendor:publish --force.
๐งช Testing
composer test
The test suite uses Pest and Orchestra Testbench.
๐ Changelog
Please see CHANGELOG for a full history of changes.
๐ค Contributing
Contributions are welcome! Please read the Contributing Guide before submitting a pull request.
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-new-feature - Commit your changes:
git commit -m 'Add some feature' - Push to the branch:
git push origin feature/my-new-feature - Open a Pull Request
๐ Security
- Never commit your
.envfile or exposeZHYLON_AUTH_CLIENT_SECRETpublicly. - Store tokens (
zhylon_token,zhylon_refresh_token) encrypted in the database using Laravel's encrypted casting if your threat model requires it. - The callback route should be protected against CSRF. Laravel Socialite handles the
stateparameter automatically to prevent CSRF attacks during the OAuth flow. - If you discover a security vulnerability, please do not use the public issue tracker. Instead, send an email to security@zhylon.net. All security reports are addressed promptly.
๐ Credits
๐ License
The MIT License (MIT). Please see the License File for details.