Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Clerk Laravel Package

ronasit/laravel-clerk

A Laravel package that integrates Clerk authentication: provides a Clerk guard and middleware for route protection, verifies sessions, syncs Clerk users into your app, and handles Clerk webhooks so you can manage authentication without building it yourself.

View on GitHub
Deep Wiki
Context7

Getting Started

This package wires Clerk (hosted auth provider) into a Laravel app so you can authenticate API/frontend requests with Clerk-issued JWTs without hand-rolling JWKS fetching and signature verification.

Minimal path:

  1. composer require ronasit/laravel-clerk — 1.2 requires PHP 8.3–8.5 and Laravel 11/12/13. If you're on PHP 8.2 or Laravel 10, stay on 1.1.
  2. Publish the config (php artisan vendor:publish and pick the clerk config) and set the env vars from the README. In 1.2 the signer key is a base64-encoded env var, so your existing CLERK_SIGNER_KEY value must be re-encoded (see Gotchas).
  3. Register the guard/middleware the README documents on the routes you want protected — typically your api group, not web.
  4. First use case: protect a single /api/me route, hit it with a real Clerk session token from your frontend, and confirm the resolved user. That exercises config, key parsing, and token verification end to end before you roll it out.

Where to look first: the README's config block and the testing section (added/changed in this release), then the package's own tests — they're the most reliable reference for expected config keys and trait usage. The package's TokenMockTrait is the fastest way to see exactly what claims the verifier expects.

Implementation Patterns

Guard-based auth. The common pattern is a dedicated clerk guard so existing session auth keeps working alongside it. Apply it per-route-group rather than globally, so public endpoints and health checks aren't paying verification cost.

User resolution. Clerk is the identity source; your users table is the profile source. Resolve by the Clerk subject (sub) claim, and use firstOrCreate keyed on that column to keep local users in sync lazily on first authenticated request. Do not key on email — Clerk lets users change it, and emails aren't guaranteed unique across providers.

Testing with TokenMockTrait. This is the biggest day-to-day win. In feature tests, use the trait to mint a valid signed token instead of mocking the guard — that way middleware, claim validation, and expiry handling are actually exercised. 1.2 changes two things here: the trait writes public_key.pem to the testing storage disk rather than into tests/, and the trait itself was refactored. Point config('filesystems.disks.testing') (or the disk name the trait documents) at a writable path, and add that path to .gitignore — otherwise you'll get stray key files in commits and flaky CI on read-only checkouts.

Per-test token shaping. Build a small helper in your base TestCase that calls the trait with overrides for sub/exp so individual tests express intent ("expired token", "wrong audience") rather than repeating full claim arrays. Keep one test asserting an unsigned/garbage token is rejected — mocking bypasses exactly the code you care about.

Integration tips.

  • Keep the Clerk secret/signer key in your secret manager, not .env.example, and mirror the base64 encoding step in CI so tests and deploys agree.
  • If you run multiple environments (staging/prod) against different Clerk instances, make the key a per-environment value and never share a token across them.
  • Pair the package with a thin ClerkUser value object or a resolveUser() action so controllers don't touch raw claims.
  • Run vendor/bin/pint in CI — 1.2 ships a Pint config, so match its preset to avoid churn when the package updates.

Gotchas and Tips

The 1.2 breaking change. The signer key is now stored base64-encoded. A raw PEM in an env var with literal newlines was always fragile (Docker, Kubernetes secrets, .env parsing). Encode it: base64 -w0 public_key.pem, then set that as the env value. If verification starts failing with a key-parse or signature error right after upgrading, this is almost certainly why — check for a value that still starts with -----BEGIN rather than base64. Treat it as a coordinated deploy: the new app code cannot read the old key format.

Multi-line env values. Even with base64 this is now a non-issue, but be aware that any wrapper script re-exporting the value must not wrap or truncate it; a 64-char line-wrapped base64 string will decode to garbage.

TokenMockTrait file location. Because 1.2 writes public_key.pem to the testing storage disk, tests that previously assumed the file sat in tests/ (custom cleanup, .gitignore entries, parallel-test isolation) need updating. Under parallel testing (--parallel), make sure each process either uses the same file safely or the disk path is per-process; concurrent writes to one key file is the classic source of intermittent failures here.

Clock and claim skew. Signed-token tests are sensitive to exp/nbf boundaries and any allowed clock skew. Use generous offsets in fixtures, and Carbon::setTestNow() (with teardown) rather than sleep().

Debugging verification failures. Wrap the first rollout with temporary logging of which check failed (signature vs. expiry vs. audience/issuer) — not the token itself, which is a bearer credential. Never log raw JWTs, even in local dev, because they end up in shared log aggregation.

Extension points. The published config is the intended customization surface. If you need per-route claim rules (e.g. an org_id requirement for tenant routes), implement that as your own middleware layered after the package's, rather than forking the verifier — that keeps upgrades cheap across Laravel 11→13.

Version pinning. 1.2's dependency bumps and Laravel 13 support mean the package is moving; pin ^1.2 and read release notes before minor bumps, since this project is pre-2.0 and uses breaking changes within minor versions.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums