lifewind / laravel-sso-client
Laravel SSO client for LifeWind authentication
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/lifewind/laravel-sso-client
Requires
- php: ^8.1
- firebase/php-jwt: ^6.0
- guzzlehttp/guzzle: ^7.5
- illuminate/auth: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
Requires (Dev)
- mockery/mockery: ^1.5
- orchestra/testbench: ^8.0|^9.0
- phpunit/phpunit: ^10.0
README
API-only SSO authentication for Laravel backends.
This package provides secure JWT-based authentication endpoints for validating OAuth tokens from frontend applications.
๐ Features
- โ API-Only Architecture: Pure JSON endpoints, no redirects
- โ JWT Authentication: Secure token-based authentication
- โ OAuth 2.0 Flow: Industry standard OAuth implementation
- โ User Management: Automatic user creation and updates
- โ CORS Ready: Cross-domain frontend support
- โ Frontend Agnostic: Works with Vue, React, Angular, or any frontend
๐ Prerequisites: Register Your App in LifeWind Core
Before installing this package, you need an OAuth client registered in LifeWind Core:
- Login to the LifeWind Core admin panel at
https://lifewind-core.test/admin(or your production URL) - Navigate to OAuth Clients โ Create Client
- Fill in:
- Name: Your app name (e.g. "Atlas")
- Redirect URI: Your frontend callback URL (e.g.
https://your-app.com/sso/callback) - Grant Type: Authorization Code
- After creation, copy the Client ID and Client Secret โ you'll need these for your
.env
Tip: For local development, use
http://localhost:3001/sso/callbackas the redirect URI (adjust port to match your frontend dev server).
๐ Quick Start
1. Installation
composer require lifewind/laravel-sso-client
2. Configuration
Publish configuration and run migrations:
php artisan vendor:publish --provider="LifeWind\SSO\SSOServiceProvider"
php artisan migrate
3. Environment Setup
# LifeWind SSO Configuration LIFEWIND_SSO_BASE_URL=https://lifewind-core.your-domain.com LIFEWIND_SSO_CLIENT_ID=your_oauth_client_id LIFEWIND_SSO_CLIENT_SECRET=your_oauth_client_secret LIFEWIND_SSO_REDIRECT_URI=https://your-frontend.com/sso/callback LIFEWIND_SSO_CREATE_USERS=true LIFEWIND_SSO_UPDATE_USERS=true # JWT Configuration LIFEWIND_SSO_JWT_SECRET=your-256-bit-secret-key LIFEWIND_SSO_JWT_EXPIRY=86400
4. CORS Configuration
Update config/cors.php:
return [ 'paths' => ['api/*', 'sso/*'], 'allowed_origins' => ['https://your-frontend.com'], 'allowed_headers' => ['*'], 'allowed_methods' => ['*'], 'supports_credentials' => false, // JWT in Authorization header ];
๐ก API Endpoints
The package automatically registers these endpoints:
| Method | Endpoint | Description |
|---|---|---|
POST |
/sso/validate |
Validate OAuth code โ return JWT + user |
GET |
/sso/user |
Get authenticated user (Bearer token) |
POST |
/sso/refresh |
Refresh JWT token |
POST /sso/validate
Exchange OAuth authorization code for JWT token.
Request:
{
"code": "oauth_authorization_code_from_callback",
"state": "oauth_state_parameter",
"redirect_uri": "https://your-frontend.com/sso/callback"
}
Success Response (200):
{
"success": true,
"user": {
"id": 1,
"email": "user@example.com",
"name": "John Doe",
"lifewind_uuid": "550e8400-e29b-41d4-a716-446655440000"
},
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"expires_in": 86400
}
Error Response (400):
{
"success": false,
"error": "Token validation failed: Invalid authorization code"
}
GET /sso/user
Get current authenticated user information.
Headers:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
Accept: application/json
Success Response (200):
{
"authenticated": true,
"local_user": {
"id": 1,
"email": "user@example.com",
"name": "John Doe",
"lifewind_uuid": "550e8400-e29b-41d4-a716-446655440000"
},
"authenticated_via": "jwt",
"token_expiry": "2024-01-15T14:30:00.000Z"
}
Error Response (401):
{
"error": "Invalid or expired authentication token",
"authenticated": false
}
POST /sso/refresh
Refresh an existing JWT token.
Headers:
Authorization: Bearer current_jwt_token
Accept: application/json
Success Response (200):
{
"success": true,
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"expires_in": 86400,
"token_expiry": "2024-01-16T14:30:00.000Z"
}
๐ Protecting Routes
Use the built-in middleware to protect your API routes:
// routes/api.php Route::middleware(['lifewind.auth'])->group(function () { Route::get('/dashboard', [DashboardController::class, 'index']); Route::apiResource('projects', ProjectController::class); Route::get('/profile', [UserController::class, 'profile']); });
๐ ๏ธ Using in Controllers
Access the authenticated user in your controllers:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Http\JsonResponse; class DashboardController extends Controller { public function index(Request $request): JsonResponse { // The middleware ensures this user is authenticated $user = $request->user(); // Returns User model instance return response()->json([ 'message' => "Welcome {$user->name}!", 'user' => [ 'id' => $user->id, 'email' => $user->email, 'name' => $user->name, 'lifewind_uuid' => $user->lifewind_uuid, ], 'dashboard_data' => [ 'recent_activity' => '...', 'notifications' => '...' ] ]); } }
๐ง Advanced Configuration
Custom User Model
If you're using a custom User model:
// config/lifewind-sso.php 'user' => [ 'model' => App\Models\CustomUser::class, 'create' => true, 'update' => true, 'fields' => [ 'email' => 'email', 'name' => 'name', 'lifewind_uuid' => 'lifewind_uuid', ], ],
JWT Configuration
# JWT Settings LIFEWIND_SSO_JWT_SECRET=your-super-secure-256-bit-secret-key LIFEWIND_SSO_JWT_EXPIRY=86400 # 24 hours in seconds LIFEWIND_SSO_JWT_ALGORITHM=HS256 # Signing algorithm
OAuth Scopes
# Request specific scopes from LifeWind LIFEWIND_SSO_SCOPES="openid,profile,email,roles"
Database Configuration
# User creation/update behavior LIFEWIND_SSO_CREATE_USERS=true # Create new users automatically LIFEWIND_SSO_UPDATE_USERS=true # Update existing users from SSO data
๐งช Testing & Debugging
Test Command
# Test SSO configuration php artisan sso:test # Test with detailed output php artisan sso:test --verbose # Test specific environment php artisan sso:test --env=staging
Manual Testing
Test the endpoints manually:
# 1. Test validation endpoint curl -X POST https://your-backend.com/sso/validate \ -H "Content-Type: application/json" \ -d '{ "code": "test_auth_code", "state": "test_state", "redirect_uri": "https://your-frontend.com/sso/callback" }' # 2. Test user endpoint with returned token curl -X GET https://your-backend.com/sso/user \ -H "Authorization: Bearer YOUR_JWT_TOKEN" \ -H "Accept: application/json"
๐ Frontend Integration
This package is designed for frontend-initiated OAuth flows:
Flow Overview
- Frontend redirects user to LifeWind OAuth provider
- LifeWind authenticates user and redirects back to frontend
- Frontend captures authorization code from callback URL
- Frontend sends code to your backend's
/sso/validateendpoint - Backend validates code with LifeWind and returns JWT + user data
- Frontend stores JWT token for subsequent API requests
For Vue.js Applications
Use our companion Vue.js package:
npm install lifewind-vue-sso-client
<template> <LifeWindSSOButton @success="handleAuth" button-text="Login with LifeWind" /> </template> <script setup> import { LifeWindSSOButton } from 'lifewind-vue-sso-client' const handleAuth = (result) => { console.log('Authenticated:', result.user) // Token automatically stored, ready for API calls } </script>
For Other Frontends
Implement the OAuth flow manually:
// 1. Redirect to OAuth provider const authUrl = `https://lifewind-core.com/oauth/authorize?` + `client_id=YOUR_CLIENT_ID&` + `redirect_uri=${encodeURIComponent('https://your-frontend.com/callback')}&` + `response_type=code&` + `state=${generateRandomState()}&` + `scope=openid profile email` window.location.href = authUrl // 2. Handle callback (in your callback page) const urlParams = new URLSearchParams(window.location.search) const code = urlParams.get('code') const state = urlParams.get('state') // 3. Validate with your backend const response = await fetch('https://your-backend.com/sso/validate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code, state, redirect_uri: 'https://your-frontend.com/callback' }) }) const result = await response.json() if (result.success) { // Store JWT token for API requests localStorage.setItem('auth_token', result.token) localStorage.setItem('user', JSON.stringify(result.user)) }
๐จ Production Checklist
Security Requirements
- HTTPS Only: Both frontend and backend must use HTTPS
- Strong JWT Secret: Use a secure 256-bit random key
- CORS Origins: Only allow your actual frontend domains
- Environment Variables: All secrets properly configured
- SSL Verification: Enable SSL verification for OAuth requests
Example Production Configuration
# Production Environment APP_ENV=production APP_DEBUG=false APP_URL=https://api.your-domain.com # LifeWind SSO (Production) LIFEWIND_SSO_BASE_URL=https://sso.lifewind.com LIFEWIND_SSO_CLIENT_ID=prod_client_id_here LIFEWIND_SSO_CLIENT_SECRET=prod_client_secret_here LIFEWIND_SSO_REDIRECT_URI=https://app.your-domain.com/sso/callback LIFEWIND_SSO_JWT_SECRET=your-production-256-bit-secret-key LIFEWIND_SSO_VERIFY_SSL=true # Remove all localhost/development origins from CORS!
Performance Optimization
// config/lifewind-sso.php 'cache' => [ 'user_data' => true, // Cache user data lookups 'ttl' => 300, // 5 minutes ], 'rate_limiting' => [ 'validate' => '10,1', // 10 requests per minute 'user' => '60,1', // 60 requests per minute 'refresh' => '5,1', // 5 requests per minute ],
๐ Troubleshooting
Common Issues
"Invalid authorization code" error:
- Check that
LIFEWIND_SSO_REDIRECT_URImatches exactly what you registered - Ensure the authorization code hasn't expired (usually 10 minutes)
- Verify the
redirect_urisent to/sso/validatematches OAuth registration
CORS errors:
- Add your frontend domain to
config/cors.php - Ensure
Access-Control-Allow-Credentialsis properly configured - Check that preflight OPTIONS requests are handled
JWT token invalid:
- Verify
LIFEWIND_SSO_JWT_SECRETis the same across all app instances - Check token hasn't expired (
expires_inseconds) - Ensure Bearer token format:
Authorization: Bearer <token>
Debug Logging
Enable detailed logging in development:
LOG_LEVEL=debug LIFEWIND_SSO_DEBUG=true
Check logs at:
tail -f storage/logs/laravel.log | grep SSO
๐ License
MIT License. See LICENSE for details.
๐ค Support
- Documentation: https://docs.lifewind.com/laravel-sso
- Issues: GitHub Issues
- Email: support@lifewind.com
Built for modern API-first applications ๐