authos-client-laravel maintained by rishadblack
Authos Client for Laravel
The official Laravel client for Authos. Add hosted social login to an existing Laravel application without moving its users, passwords, sessions, or authorization rules into Authos.
The package provides:
- a Blade button block for the providers enabled for your application;
- signed, short-lived state for login, sign-up, and account-connection flows;
- a callback route that exchanges one-time codes server to server;
- a signed webhook endpoint and Laravel event;
- methods for links, identities, users, tenants, and event recovery;
- an in-memory fake for application tests.
Your application decides what every accepted or rejected result means. It keeps its own registration, authentication, sessions, two-step verification, permissions, and user records.
Contents
- Requirements
- Installation
- Authos application setup
- Configuration
- Handle callback results
- Render provider buttons
- Connect another provider
- Handle webhooks
- Client methods
- Errors
- Testing
- Security notes
- License
Requirements
| Dependency | Version |
|---|---|
| PHP | 8.3 or newer |
| Laravel | 12 or 13 |
Installation
composer require rishadblack/authos-client-laravel
php artisan vendor:publish --tag=authos-config
Laravel discovers Authos\Laravel\AuthosServiceProvider automatically. Publishing the configuration is
optional; environment variables are enough for the standard setup.
Authos application setup
Create an application in the Authos dashboard, then add the exact callback and webhook addresses used by your Laravel application.
Default addresses:
https://your-app.example/auth/authos/callback
https://your-app.example/api/webhooks/authos
Copy the application id, application secret, and webhook secret into .env:
AUTHOS_URL=https://auth.sylloo.com
AUTHOS_CLIENT_ID=app_your_public_id
AUTHOS_SECRET=sk_your_key_id.your_secret
AUTHOS_WEBHOOK_SECRET=whsec_your_webhook_secret
Never expose AUTHOS_SECRET or AUTHOS_WEBHOOK_SECRET to a browser, mobile application, log, or public
repository.
Configuration
The published config/authos.php supports these settings:
| Environment variable | Default | Purpose |
|---|---|---|
AUTHOS_URL |
https://auth.sylloo.com |
Authos service address |
AUTHOS_CLIENT_ID |
none | public application id |
AUTHOS_SECRET |
none | server-side application secret |
AUTHOS_WEBHOOK_SECRET |
none | verifies incoming webhook signatures |
AUTHOS_ROUTES |
true |
registers the package callback and webhook routes |
AUTHOS_CALLBACK_PATH |
auth/authos/callback |
callback route path |
AUTHOS_WEBHOOK_PATH |
api/webhooks/authos |
webhook route path |
AUTHOS_DOMAIN |
none | optional host used by both package routes |
AUTHOS_REDIRECT_URI |
generated callback URL | exact callback registered in Authos |
AUTHOS_BIND_STATE_TO_SESSION |
true |
binds signed state to the browser session |
AUTHOS_REMEMBER_DOMAIN |
current host | cookie domain for the last successful provider |
Use AUTHOS_DOMAIN when callbacks and webhooks must exist only on one central host. Set an explicit
AUTHOS_REDIRECT_URI when Laravel cannot generate the public callback address correctly.
Keep session binding enabled for a normal application. A multi-host application may disable it when the
button and callback are necessarily on different hosts, but should carry its own nonce in state and
verify it on the original host with Authos::pullNonce().
Inspect the registered routes with:
php artisan route:list --name=authos
Handle callback results
The callback route is registered only after the application binds
Authos\Laravel\Contracts\HandlesAuthosResult. Create a class that translates Authos results into your
application's own sign-in, registration, refusal, or account-linking flow:
<?php
namespace App\Authos;
use Authos\Laravel\Contracts\HandlesAuthosResult;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
final class AuthosResultHandler implements HandlesAuthosResult
{
public function handle(array $result, array $state, Request $request): Response
{
if (($result['result'] ?? null) === 'rejected') {
return redirect()->route('login')->withErrors([
'authos' => 'This social login could not be used.',
]);
}
// Call your application Action here. Match or create the local user according
// to your own rules, run any required two-step check, then start your session.
return redirect()->intended($state['return'] ?? route('dashboard'));
}
public function failed(string $reason, Request $request): Response
{
return redirect()->route('login')->withErrors([
'authos' => 'The social login expired. Please try again.',
]);
}
}
Bind it in a service provider:
use App\Authos\AuthosResultHandler;
use Authos\Laravel\Contracts\HandlesAuthosResult;
public function register(): void
{
$this->app->bind(HandlesAuthosResult::class, AuthosResultHandler::class);
}
The handler receives:
$result: the verified exchange response, includingresult,reason,attempt,user,identity, andlinkwhen applicable;$state: values signed when the button URL was built, such asintent,tenant,kind,return, and your customstatevalues;$request: the Laravel callback request.
Do not trust a browser-supplied user id or email. Use only the verified exchange result and enforce your normal local authorization and account-matching rules.
Render provider buttons
Place the component under the application's existing sign-in or registration form:
<x-authos-buttons intent="login" return="/dashboard" />
For a tenant-aware application:
<x-authos-buttons
intent="signup"
:tenant="$business->getKey()"
kind="customer"
:state="['host' => request()->getHost()]"
return="/account"
/>
Available component properties:
| Property | Default | Purpose |
|---|---|---|
intent |
login |
login, signup, or connect |
tenant |
none | application-defined tenant identifier |
kind |
none | application-defined local user kind |
return |
none | signed local destination for the handler |
login-hint |
none | email hint sent to the provider |
connect-token |
none | proof used by a signed-in user connecting a provider |
choose-account |
false |
asks the provider to show its account chooser |
state |
[] |
additional values included in signed state |
Enabled providers are cached for ten minutes. If Authos is unavailable, the component renders nothing after a short timeout, leaving the application's normal form usable.
Build an individual URL through dependency injection or the facade when you need custom markup:
use Authos\Laravel\Facades\Authos;
$url = Authos::connectUrl('login', 'google', [
'tenant' => (string) $business->getKey(),
'kind' => 'member',
'return' => '/dashboard',
'prompt' => 'select_account',
'state' => ['host' => request()->getHost()],
]);
Connect another provider
A connect flow starts from an already authenticated local account. First request a short-lived connect token on the server, then give it to the button component:
use Authos\Laravel\Facades\Authos;
$proof = Authos::connectToken(
externalId: (string) $user->getKey(),
tenant: $business->getKey(),
kind: 'member',
sub: $user->authos_sub,
);
<x-authos-buttons
intent="connect"
:tenant="$business->getKey()"
kind="member"
:connect-token="$proof['connect_token']"
return="/profile/security"
/>
Only issue connect tokens after authenticating and authorizing the local user.
Handle webhooks
The package verifies Authos-Id, Authos-Timestamp, and Authos-Signature before dispatching
AuthosWebhookReceived. Invalid or stale signatures receive HTTP 401.
Register a listener in your application:
<?php
namespace App\Listeners;
use Authos\Laravel\Events\AuthosWebhookReceived;
use Illuminate\Contracts\Queue\ShouldQueue;
final class ApplyAuthosEvent implements ShouldQueue
{
public function handle(AuthosWebhookReceived $event): void
{
// Make this idempotent: store $event->id before applying the change.
// Handle the event type through your application's own Actions.
}
}
Important event types include user.updated, user.merged, user.deleted, link.removed, and
attempt.flagged. Events can be delivered more than once or out of order. Queue processing, keep every
processed event id, and ignore duplicates.
If delivery was interrupted, recover events from the API:
$page = Authos::events(after: $lastEventId, types: ['user.merged', 'user.deleted']);
Client methods
Use Authos\Laravel\Facades\Authos or inject Authos\Laravel\Authos.
| Method | Purpose |
|---|---|
connectUrl($intent, $provider, $options) |
build a hosted-flow URL with signed state |
exchange($code, $externalId, $metadata, $kind) |
exchange a one-time callback code |
connectToken($externalId, $tenant, $kind, $sub) |
authorize a connect flow for a local user |
link($sub, $tenant, $kind, $externalId, $metadata) |
connect an Authos account to a local record |
removeLink($sub, $tenant) |
remove one application or tenant link |
removeTenant($tenant) |
request removal of every link for a deleted tenant |
disconnect($sub, $provider) |
remove one provider identity |
user($sub) |
read the application's view of an Authos account |
block($sub, $tenant, $blocked) |
block or unblock social login |
providers() |
get enabled providers, cached for ten minutes |
events($after, $types) |
recover application events |
readState($state) |
verify and consume signed callback state |
pullNonce($nonce) |
consume a session nonce in a multi-host flow |
Every write automatically receives a unique Idempotency-Key. Authos returns machine-readable error
codes when it refuses a request.
Errors
API and connection failures throw Authos\Laravel\AuthosException:
use Authos\Laravel\AuthosException;
use Authos\Laravel\Facades\Authos;
try {
$user = Authos::user($sub);
} catch (AuthosException $exception) {
report($exception);
$code = $exception->errorCode; // e.g. unauthorized, link_not_found, unreachable
$status = $exception->status; // 0 when the service could not be reached
}
Show plain application-owned messages to users. Do not expose secrets, raw upstream responses, or stack traces.
Testing
Replace the client with its fake in a Pest or PHPUnit test:
use Authos\Laravel\Facades\Authos;
$authos = Authos::fake()->respond('/api/v1/attempts/exchange', [
'result' => 'signed_in',
'user' => ['sub' => 'usr_example', 'email' => 'person@example.com'],
'attempt' => ['provider' => 'google'],
]);
// Exercise your callback or Action.
$authos->assertSent('/api/v1/attempts/exchange', function (array $call): bool {
return $call['method'] === 'post'
&& $call['data']['code'] === 'one_time_code';
});
Other helpers:
$authos->respond('/api/v1/users/usr_example', ['data' => ['sub' => 'usr_example']]);
$authos->assertSent('/api/v1/users/usr_example');
$authos->assertNothingSent();
The fake signs and verifies state with the same implementation as the real client. By default, its provider list contains Google and GitHub; queue a provider response when a test needs another list.
Security notes
- Keep application and webhook secrets on the server.
- Register exact callback addresses in Authos and use HTTPS in production.
- Keep signed state bound to the session unless the application has a deliberate multi-host design.
- Treat callback codes and connect tokens as short-lived, one-time values.
- Authorize local writes before calling
link,disconnect,removeLink,removeTenant, orblock. - Process webhooks idempotently and in a queue.
- Continue enforcing the application's own two-step verification and session rules after social login.
- Do not use an unverified provider email as proof of account ownership.
License
Authos Client for Laravel is open-source software licensed under the MIT License.