mustafa-azmi/laravel-checkin

Signed, single-use, time-limited check-in tokens for any Eloquent model — event attendance, gyms, coworking, deliveries. QR-agnostic: pair with any QR/barcode renderer you like.

Maintainers

Package info

github.com/Mustafa21102005/laravel-checkin

pkg:composer/mustafa-azmi/laravel-checkin

Transparency log

Statistics

Installs: 12

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.0.0 2026-08-13 11:44 UTC

This package is auto-updated.

Last update: 2026-08-14 13:14:30 UTC


README

tests Latest Version PHP Version Laravel Version License

Signed, time-limited, single-use check-in tokens for any Eloquent model — event attendance, classes, gym entry, coworking access, deliveries. QR-agnostic by design: pair it with whatever QR/barcode renderer you like, or don't use QR at all.

Originally generalized from a university attendance system (ScanTrack) into a package that works for any "someone needs to prove they showed up" use case.

Table of contents

Try it live

A full demo app is deployed and running — create an event, issue a real signed pass, scan it with your camera or type it manually, and see every outcome (success, already-used, expired, invalid) play out for real.

laravel-checkin.alwaysdata.net →

Demo source: laravel-checkin-demo

Why this exists

Most check-in / attendance features get hand-rolled per project, with the same recurring mistakes:

  • storing raw tokens that can be screenshotted or copied and reused indefinitely
  • no expiry, so a leaked code works forever
  • no protection against two people scanning/submitting the same code at the same instant and both being marked present

This package solves all three, and attaches to any model with one trait — verified with automated tests across PHP 8.2/8.3/8.4 and Laravel 10/11/12/13 on every push (see the badge above).

Installation

composer require mustafa-azmi/laravel-checkin

php artisan vendor:publish --tag=checkin-migrations
php artisan vendor:publish --tag=checkin-config # optional
php artisan migrate

Usage

Add the trait to any model that should be "checkinable":

use MustafaAzmi\Checkin\Traits\HasCheckins;

class Event extends Model
{
    use HasCheckins;
}

Generate a token (e.g. when an attendee registers). This package doesn't render QR codes itself — pick any renderer you like and hand it the payload:

$generated = $event->generateCheckinToken(user: $attendee);

// $generated->raw is the ONLY time you'll ever see the raw token —
// it is never stored. Put it into a QR code with, e.g. endroid/qr-code:
$qrCode = \Endroid\QrCode\QrCode::create($generated->toQrPayload());

At the door, redeem the scanned/submitted token:

use MustafaAzmi\Checkin\Facades\Checkin;
use MustafaAzmi\Checkin\Exceptions\{
    TokenNotFoundException,
    TokenExpiredException,
    TokenAlreadyUsedException,
};

try {
    $token = Checkin::redeem($scannedValue);
    // ✅ checked in — $token->tokenable is the Event, $token->user_id is the attendee
} catch (TokenNotFoundException) {
    // not a valid code
} catch (TokenExpiredException) {
    // expired — code was valid but too old
} catch (TokenAlreadyUsedException) {
    // already checked in — flag as a possible duplicate/fraud attempt
}

Want to preview a code without consuming it (e.g. show attendee details on a screen before staff confirms)? Use validate() instead of redeem() — identical checks, but doesn't mark the token as used.

Design notes

  • Tokens are HMAC-hashed, never stored raw. A full database leak cannot be used to forge or replay check-ins without also having APP_KEY.
  • Redemption is wrapped in a locked transaction (lockForUpdate), so concurrent scans of the same single-use code cannot both succeed — see tests/CheckinTokenServiceTest.php for the test proving this.
  • Polymorphic by design — one checkin_tokens table serves every model in your app that adopts the trait, rather than a bespoke table per feature.
  • single_use is configurable per-token, not just globally — so the same package handles both "one-time event ticket" and "reusable gym door pass" patterns.
  • QR-agnostic — the package hands you a signed payload string; how you deliver it (QR image, barcode, plain text link, NFC) is entirely up to you.

Testing

composer install
vendor/bin/pest

CI runs the full suite against every combination of PHP 8.2/8.3/8.4 and Laravel 10.x/11.x/12.x/13.x on every push — see .github/workflows/tests.yml.

License

MIT — see LICENSE.md.