PHP and Laravel
PHP 8.1+ with ext-curl and ext-json, no other dependencies. TausiBackend (secret key) protects your API and manages users; TausiClient (publishable key) signs users in from server-rendered pages and keeps the token in $_SESSION.
Install
tausi/tausi-php on PackagistRequires PHP 8.1+ with ext-curl and ext-json; no other dependenciescomposer require tausi/tausi-phpTAUSI_URL=https://tausi-auth.onrender.com
TAUSI_PUBLISHABLE_KEY=pk_…
TAUSI_SECRET_KEY=sk_…Protect your API
<?php
use Tausi\TausiBackend;
$tausi = new TausiBackend(getenv('TAUSI_URL'), getenv('TAUSI_SECRET_KEY'));
$auth = $tausi->authenticateRequest(); // reads Authorization: Bearer <token> from $_SERVER
if ($auth === null) {
http_response_code(401);
exit(json_encode(['error' => 'Unauthorized']));
}
echo json_encode(['id' => $auth->user->id, 'email' => $auth->user->email]);authenticateRequest() and verifySession($token) return null for invalid, expired, revoked or banned sessions, and throw TausiException only for problems on your side (wrong key, network, 5xx).
Authorization header may never reach PHP. Add CGIPassAuth On, or pass the header in yourself: $tausi->authenticateRequest($request->header('Authorization')).Laravel
public function register(): void
{
$this->app->singleton(\Tausi\TausiBackend::class, fn () => new \Tausi\TausiBackend(
config('services.tausi.url'),
config('services.tausi.secret'),
));
}
// config/services.php
'tausi' => ['url' => env('TAUSI_URL'), 'secret' => env('TAUSI_SECRET_KEY')],<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Tausi\TausiBackend;
use Tausi\TausiException;
final class TausiAuth
{
public function __construct(private readonly TausiBackend $tausi) {}
public function handle(Request $request, Closure $next)
{
try {
$auth = $this->tausi->authenticateRequest($request->header('Authorization'));
} catch (TausiException) {
return response()->json(['error' => 'Authentication unavailable'], 503);
}
if ($auth === null) {
return response()->json(['error' => ['code' => 'UNAUTHENTICATED']], 401);
}
$request->attributes->set('tausi', $auth);
return $next($request);
}
}->withMiddleware(fn ($m) => $m->alias(['tausi' => \App\Http\Middleware\TausiAuth::class]))
Route::middleware('tausi')->get('/me', fn (Request $r) => $r->attributes->get('tausi')->user->toArray());Server-rendered sign-in
When PHP renders the forms itself, use TausiClient. The token stays in $_SESSION on the server and never reaches the browser:
<?php
use Tausi\TausiClient;
use Tausi\TausiException;
use Tausi\TokenStore\PhpSessionTokenStore;
session_start();
$tausi = new TausiClient(getenv('TAUSI_URL'), getenv('TAUSI_PUBLISHABLE_KEY'), new PhpSessionTokenStore());
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$tausi->signIn($_POST['email'], $_POST['password']); // also regenerates the PHP session id
header('Location: /dashboard');
exit;
} catch (TausiException $e) {
$error = match ($e->errorCode) {
'INVALID_CREDENTIALS' => 'Wrong email or password.',
'EMAIL_NOT_VERIFIED' => 'Check your inbox to verify your email first.',
default => $e->getMessage(), // ACCOUNT_BANNED, ACCOUNT_SUSPENDED, RATE_LIMITED, ...
};
}
}
// On protected pages:
$auth = $tausi->getSession(); // AuthResult or null (no request without a token)
if ($auth === null) { header('Location: /sign-in'); exit; }$tausi->signUp($email, $password, $name, [
'username' => 'asha', 'phoneNumber' => '+255712345678', 'timezone' => 'Africa/Dar_es_Salaam',
]); // EMAIL_ALREADY_REGISTERED (409) if the email has an account; its owner gets an email
$tausi->updateUser(['firstName' => 'Asha', 'timezone' => null]); // null clears a field
$tausi->changePassword($current, $new); // signs out other devices
$tausi->listSessions(); $tausi->revokeOtherSessions();
$tausi->signOut();Email links
// Show a button; redeem on POST so link scanners can't use the token up.
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$tausi->verifyEmail($_GET['token'] ?? '');
// reset-password.php: $tausi->resetPassword($_GET['token'] ?? '', $_POST['password']);
}
// forgot-password.php: $tausi->forgotPassword($_POST['email']);Manage users
$page = $tausi->listUsers(['q' => 'asha', 'access' => 'banned', 'pageSize' => 50]);
foreach ($page->items as $u) {
echo $u->email, ' ', $u->status, ' ', $u->activeSessions, ' ', $u->lastSignInAt, ' ', $u->access;
}
$detail = $tausi->getUser($userId); // user, sessions (devices), signInHistory, recentAudit
$tausi->updateUser($userId, ['emailVerified' => true, 'privateMetadata' => ['stripeId' => 'cus_123']]);
$tausi->suspendUser($userId, new DateTimeImmutable('+7 days'), 'Chargeback');
$tausi->banUser($userId, 'Spam'); $tausi->unbanUser($userId);
$tausi->bulkUsers('revoke_sessions', [$idA, $idB]);
$tausi->revokeUserSessions($userId);
$tausi->deleteUser($userId);See Managing users for what each action does.
Errors
Every API error is a Tausi\TausiException with status, errorCode, getMessage(), details, requestId and retryAfter. Network failures have status 0 and code NETWORK_ERROR or TIMEOUT. All codes.
To use Guzzle or Symfony HttpClient, implement Tausi\Http\HttpClient and pass it as the third argument of TausiBackend or the fourth of TausiClient.
Social sign-in