Skip to content
SESAME

Keys cut while you wait · waynestate/sesame 0.1

SESAME

Single Entry, Sessions App-Managed Everywhere.

The way in. One lock, any key.

Wayne State's protocol-neutral auth library for PHP. It hands your app a verified identity and leaves the session to the app: every driver ends in the same place, your app's findOrImportUser(Identity). Switching driver is a config change, not a code change. Open sesame.

composer require waynestate/sesame

Try a key Watch one get cut

SESAME mark: an arched door standing open, with a gold wedge of light between its leaves

Service counter. Same door for every key.

The pegboard

One blank per protocol

Five blanks hang on the board, one for each driver. The heads differ; the cut does not. Every key that's cut is cut to the same lock, your app's findOrImportUser(Identity). Pick one and try the door.

.env

SESAME_DRIVER=cas

cas: CAS 2.0 by default. The CAS server sends the user back with a ticket; SESAME validates it once, then drops it from the address bar. The door opens.

The duplicator

Swap the blank. Keep the door.

Re-keying an app from cas to gateway: the machine traces the cut on the key you have and copies it onto a new blank. Scroll, and it runs.

A key duplicator copies the cut of a cas key onto a gateway blank. As it cuts, the config line SESAME_DRIVER=gateway is typed under the new key. The new key goes into the same door, the door opens, and ab1234 is in.
  1. Clamp a gateway blank. A new head; no cut yet.
  2. Trace the cut. The tracer follows the cas key and the cutter copies it. Same lock, same cut.
  3. The cut is one config line. SESAME_DRIVER=gateway, plus the gateway's key, issuer, audience and trusted proxies. No code changes.
  4. Open sesame. Same door, same findOrImportUser(Identity). ab1234 is in.

Three doorways

Same lock, any frame

Raw PHP, Laravel with Blade, or Inertia with Vue. Install it once; the door is the same.

Install Windows, macOS and Linux: the same line

composer require waynestate/sesame

Job 01

Raw PHP

The app owns the session: start it yourself, and let HELMET set the cookie flags. Then ask SESAME who it is.

session_start();
// build $sesame (see the README), then:
sesame($sesame);
$user = sesame_login();

Protected pages read sesame_user(). Login and logout stop the script after their redirect.

Job 02

Laravel + Blade

The service provider is discovered on its own. Publish the config, then guard a route.

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

Route::get('/dashboard', fn () => view('dashboard'))
    ->middleware('auth.sesame');

Guests go to sesame.login; a JSON guest gets a 401.

Job 03

Laravel + Inertia/Vue

The same Laravel adapter. The middleware guards the route before any Vue page is sent.

Route::get('/vault', fn () => Inertia::render('Vault'))
    ->middleware(['auth.sesame', 'sesame.mfa']);

sesame.mfa also asks that the user's MFA is still good.

No PHP on the machine?

Docker runs the suite on every supported PHP. The lines work as written in PowerShell, bash and zsh.

docker run --rm -v "${PWD}:/app" -w /app composer:2 composer install --no-interaction
docker run --rm -v "${PWD}:/app" -w /app php:8.3-cli vendor/bin/phpunit
docker run --rm -v "${PWD}:/app" -w /app php:8.4-cli vendor/bin/phpunit
docker run --rm -v "${PWD}:/app" -w /app php:8.5-cli vendor/bin/phpunit

Posted by the door

Shop rules

  1. The app owns the session. SESAME never starts one and never touches a cookie.
  2. A new session ID at login, before anything is stored in it.
  3. Fail closed. A bad answer, bad XML or an empty user ends the login. Nothing falls back to a default user.
  4. No bare headers. The gateway driver reads one signed assertion, from a trusted proxy, and each one works once.
  5. The fake key stays home. It refuses to boot in production.
  6. No default locks. Required settings have no defaults, so nobody is pointed at a server the app owner never chose.
  7. MFA fails closed. No sign-in time, no MFA method, or one that's too old: the request is denied.
  8. Logout shuts the door. Cache-Control: no-store and Clear-Site-Data: "cache", "storage", so the back button shows nothing.

Every practice, with its sources

Cross-reference

Re-key from wayne-cas

Coming from wayne-cas? You don't rewrite your auth. The shim keeps the old names and behaviour, and says once, in the log, that it's a bridge.

wayne-cas names and the SESAME names that replace them
Old part (wayne-cas)Fits (SESAME)
wayne-cas.rootsesame.cas.base_url
auth.providers.users.modelauth.providers.users.model, unchanged
WayneCasable traitimplements WayneCasable + use ReadOnlyAttributes
WayneAuthenticate middlewarethe wayne.cas middleware alias
auth()->login($user)app(Sesame::class)->user()
use2FAnot carried; the shim logs a warning once when it's on

On the key ring

SESAME in WELD

One part of Wayne State's app stack. Here's where it sits in a signed-in request, and who else is on the ring.

  1. DRAWBRIDGE signs the assertion at the edge
  2. SESAME checks it and hands over an identity
  3. HELMET hardens the session cookie
  4. WayneUI renders the signed-in page