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 Tailscale Identity Laravel Package

geocodio/laravel-tailscale-identity

Laravel package for authenticating requests with Tailscale identity headers, letting your app trust Tailscale user and device details for zero-trust access and identity-aware routes without extra auth plumbing.

View on GitHub
Deep Wiki
Context7

Getting Started

This package resolves the caller's Tailscale identity (via tailscale whois on the incoming connection) and exposes it to Laravel as a TailscaleIdentity object, with a fake driver for local/test use.

  1. composer require the package, then publish its config — look for a tailscale-identity-config tag in the service provider (php artisan vendor:publish --tag=...). Everything you need to tune lives in config/tailscale-identity.php: driver selection, the fake block, and cache settings.
  2. Read the service provider bindings before anything else. The identity is resolved through a driver interface, and TailscaleIdentity is the DTO you'll actually touch — confirm whether it's bound as a singleton per request or resolved lazily, because that determines whether you can inject it into constructors.
  3. First use case: a /whoami route that dumps login, displayName, and (new in v0.2.0) profilePictureUrl. That single route validates your whole setup — headers reaching the app, whois resolving, cache working, and the avatar field present.
  4. For local development without tailscaled running, switch to FakeIdentityDriver and populate tailscale-identity.fake.*. As of v0.2.0 that block accepts profile_picture_url, so you can develop avatar UI without a real Tailscale peer.

Implementation Patterns

Resolve once, inject afterwards. whois can shell out or hit the local API, so don't call the resolver in a loop or per-Blade-component. Bind it once (middleware that resolves and stashes on the request/container) and let controllers, views, and policies read the resolved instance.

Sync to users on first login, keyed by a stable identifier. Use the Tailscale login name or node user ID as your lookup key — never the avatar URL or display name, both of which change. Persist profile_picture_url as a nullable column with a profile_picture_synced_at timestamp, refresh it on a schedule or on login, and treat a null as "no picture" rather than "fetch failed".

Treat profilePictureUrl as a display hint, not data. It's nullable and https-only by design (UserProfile.ProfilePicURL is passed through a scheme check), so every render site needs a fallback:

<img src="{{ $identity->profilePictureUrl ?? asset('img/avatar-default.svg') }}"
     alt="{{ $identity->displayName }}">

Wrap this in a single Blade component so the fallback logic exists in one place — you'll otherwise ship three different defaults.

Proxy avatars if they're user-visible. The URL usually points at a Google/GitHub CDN. Hotlinking means every page load leaks your users' IP addresses to a third party and breaks silently if the provider rotates URLs. A small controller that streams the image through your cache solves both.

Test the avatar path explicitly with the fake driver. Set tailscale-identity.fake.profile_picture_url in a test case or via config()->set(), then write two assertions: one with a URL, one with null, so the fallback branch is covered. Also assert the non-https case is dropped — that's the behaviour the release explicitly introduces.

Don't over-cache on your side. The package already caches whois results. If you also cache the resolved identity, key it with the same version token the package uses, or you'll serve pre-v0.2.0 payloads that have no avatar field for the duration of your TTL.

Gotchas and Tips

  • The cache key prefix moved to v2. This is the release's quiet breaking-ish change: every cached whois payload from before the upgrade is now unreachable. Old v1 entries linger until their TTL expires (worth flushing on a small Redis instance), and you get a cold-cache latency spike on the first requests after deploy — noticeable if resolution shells out to the tailscale binary. Warm it or accept one slow request per user.
  • profilePictureUrl is nullable and https-only. Whois can return an empty string, an http:// URL, or nothing at all; the package filters rather than errors. Code that assumes a string will hit null in production on accounts with no linked avatar.
  • Setting the fake config value is not enough. FakeIdentityDriver only takes effect when the fake mode/driver is actually selected. A profile_picture_url sitting in config under the real driver is inert, and this is the most common reason a test "doesn't see" the avatar.
  • Don't gate anything on the picture. It's cosmetic and user-mutable upstream. It's fine for alt text and initials fallbacks; it's not an identity signal.
  • Privacy surface. Avatar URLs encode which identity provider a user authenticated with. If that's sensitive in your context, store the image rather than the URL.
  • Extension point: if you need custom resolution (e.g. a header-injection path for a reverse proxy other than Tailscale's), the driver binding is the seam — implement the identity contract and rebind, rather than forking TailscaleIdentity. Keep the DTO construction in one factory so a future field addition like this one is a one-line change.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin