exinone/mixin-sdk-php
A PHP SDK for integrating Mixin Network services into your applications. It provides convenient clients for Mixin Messenger, wallet, and blockchain APIs, enabling payments, transfers, user authentication, and digital asset management in PHP or Laravel projects.
This release (1.4.12) adds an aud (audience) parameter to the generated JWT payload, which is a small but useful additive change if you're running multi-service or multi-audience APIs. There are no breaking changes, so existing tokens and flows keep working — but you now have a first-class place to assert who a token is meant for.
Minimal setup for a typical Laravel app:
composer require <vendor>/<package>
php artisan vendor:publish --provider="<Vendor>\<Package>\Providers\LaravelServiceProvider"
JWT_SECRET into .env):
php artisan jwt:secret
config/auth.php:
'guards' => [
'api' => ['driver' => 'jwt', 'provider' => 'users'],
],
User model (getJWTIdentifier() and getJWTCustomClaims()).First use case to try: a login endpoint that returns a token, then hit a route protected by auth:api. This exercises the full issue → verify → refresh loop, and is the fastest way to confirm the guard, provider, and secret are aligned. Look first at config/jwt.php (TTL, refresh TTL, blacklist, and the new aud handling) and the package's JWTAuth/JWTGuard classes — those are where 90% of real behaviour lives.
Login / token issuance. Use auth('api')->attempt($credentials) in a controller and return respondWithToken(). Keep the controller thin — token shape and claims belong in the package's factory or a small service class, not in the request handler.
Audience-scoped tokens (new in 1.4.12). Since the payload now carries aud, use it deliberately:
aud claim on the verifying side. If the package exposes an audience expectation in config, set it; otherwise compare auth('api')->payload()->get('aud') against an allow-list in middleware.aud with the target service, not the issuer.Refresh workflow. Keep TTL short (5–15 min) and refresh TTL longer (e.g. 2 weeks), with blacklist enabled so rotated tokens can't be reused. Return token_type, expires_in, and the token in a consistent envelope — clients will hardcode this shape.
Stateless vs. stateful logout. With blacklist_enabled => true you get real revocation but pay for a cache read per request and need a shared cache across nodes. If you're running multiple app servers, verify the cache driver is Redis/Memcached — the file driver silently breaks revocation in a load-balanced setup.
Custom claims. Add per-user or per-tenant claims in getJWTCustomClaims(). Keep them small: every claim inflates every token and every request header. Never put secrets, emails you don't need, or PII you're not contractually allowed to transmit.
Integration tips.
auth:api middleware plus a refresh-tolerant client; the package's RefreshToken middleware pattern (catch TokenExpiredException, refresh, retry) avoids forcing re-login on TTL expiry.JWTAuth::fromUser($user) gives you a valid token without hitting the login route — good for feature tests, but keep one real login test so auth wiring stays covered.The new aud claim won't validate itself. Adding aud to the payload is only half the story — consumers must actually check it. If your API gateway or downstream services were ignoring audience before, they'll keep ignoring it. Decide now whether aud is advisory or enforced, and document it, otherwise you get tokens that look scoped but aren't.
Adding claims can surprise strict clients. Most JWT consumers ignore unknown claims, but if any of your services construct the payload into a fixed struct or hash it for comparison, the extra aud field changes the signature and serialized form. Test any downstream JWT verification before rolling this out.
Blacklist + Cache misconfiguration is the classic footgun: enable blacklist, forget to set a shared store, and revoked tokens work fine on the node that revoked them and nowhere else. Also remember blacklist_grace_period — set it long enough for concurrent requests carrying the old token, short enough that revocation actually means something.
Clock skew. Set leeway in config if you have services on machines with drifting clocks; otherwise you'll get intermittent "token not yet valid" errors that are maddening to reproduce.
Secret rotation. Rotating JWT_SECRET invalidates every token instantly. Plan a dual-secret window or a forced re-login; there's no built-in graceful rotation.
Config caching. php artisan config:cache after changing config/jwt.php — many "my config change did nothing" reports are just a stale cache in a container.
Extension points worth knowing. Custom claim resolvers, custom providers (if you're not authenticating Eloquent users), and the exception handler mapping (override to return consistent JSON 401/423 responses instead of the package defaults). The aud addition is a good moment to audit your claim set and lock down what you actually need — more claims means more payload, more surface area, and more to keep in sync.
How can I help you explore Laravel packages today?