Download the PHP package webpatser/resonate-token-auth without Composer

On this page you can find all versions of the php package webpatser/resonate-token-auth. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package resonate-token-auth

Resonate Token Auth

Token-based subscription auth for Resonate. Skips the /broadcasting/auth HMAC round-trip for clients that have a token (JWT by default, anything via a pluggable validator) instead of a session cookie.

The problem it solves

Resonate authenticates private and presence channel subscriptions the Pusher way: the browser POSTs socket_id + channel to your Laravel /broadcasting/auth endpoint, the endpoint reads the session, and returns an HMAC signature the client carries in pusher:subscribe. That works for browsers; it does not work as cleanly for:

This package lets a connection present a token directly to Resonate. The plugin validates it, derives the user identity from its claims, and synthesizes the HMAC signature the standard subscribe path already knows how to verify, so the rest of Resonate runs unchanged.

How it works

One verify path, two ways to feed it

When a pusher:subscribe arrives with a token field instead of an auth field, the plugin:

  1. validates the token via the configured TokenAuthenticator (JWT by default),
  2. checks that the token is bound to the application it was presented on,
  3. asks the ChannelAuthorizer whether the claims may subscribe to this channel,
  4. for presence channels, builds the channel_data from the token's user_id (and optional user_info),
  5. computes the same HMAC signature /broadcasting/auth would have returned, using the app's secret,
  6. hands the rewritten payload to EventHandler::handle() so the standard subscribe path runs.

Because the plugin signs with the same secret the verifier checks against, the standard InteractsWithPrivateChannels::verify() accepts the synthesized signature without ever knowing the plugin was involved. The subscription_succeeded frame, the presence member_added broadcast, the plugin lifecycle hooks: all of it runs.

Per-subscribe or pre-authenticated

The plugin supports two equivalent flows. Pick whichever fits your client.

Per-subscribe (stateless). Include the token on every subscribe:

Pre-authenticated (cached). Authenticate once, then subscribe without a token:

The plugin replies with app:authenticated and caches the validated claims on the connection. Subsequent subscribes need no token:

The two flows coexist. A per-subscribe token always overrides the cached claims, so a stateless client never depends on connection-bound state.

Cached claims are re-checked against their exp (plus leeway) on every subscribe. A connection that pre-authenticated with a five minute token stops being able to open new subscriptions once those five minutes are up, instead of coasting for the life of the socket. The rejection carries reason expired_token. Existing subscriptions are left alone; the client either sends a fresh token with the next subscribe (which overrides the stale cache) or reconnects and pre-authenticates again.

Tokens are bound to one application

Resonate can serve several applications from one process, each with its own key and secret, while the JWT settings here are a single global block. Without a binding claim a token minted for tenant A verifies just as well on tenant B's app key, and the plugin would then synthesize B's HMAC for it: A's user lands inside B's private and presence channels.

So every token has to name the application it was minted for, in an app_id claim by default:

The value is matched against the connection's Resonate application id (app_id in config/reverb.php, not the app key). A token naming a different application is always rejected, with a pusher:error and a TokenRejected event carrying reason application_mismatch.

Migrating existing issuers. Requiring the claim is the default, so an upgrade rejects tokens minted before you started sending it. To roll out without downtime:

  1. Set RESONATE_TOKEN_AUTH_REQUIRE_APP_CLAIM=false (or 'require_app_claim' => false in the published config) and deploy. Tokens without the claim keep working; tokens naming the wrong application are still rejected, because the switch only forgives a missing claim, never a mismatch.
  2. Add 'app_id' => config('reverb.apps.apps.0.app_id') to whatever mints your tokens, and let the old ones expire.
  3. Put the switch back to true.

Single-application servers are not exposed to the cross-tenant problem, but the claim is still required by default there: it costs one line at the issuer and it means adding a second app later cannot quietly open a hole.

Coexists with HMAC

A pusher:subscribe that already carries an auth field is relayed untouched: the standard /broadcasting/auth flow runs. Browser clients with cookies keep working; token clients use the new path. They share the same server, the same channels, the same presence semantics.

Installation

Publish the config if you want to change defaults:

Registering the plugin

Restart Resonate (php artisan resonate:start, or resonate:reload for a zero-downtime swap).

Configuration

Key Default Purpose
algorithm HS256 JWT signing algorithm. HS256/384/512 (shared secret) or RS256/384/512, ES256/384 (public key).
secret null Shared secret for HS* algorithms.
public_key null PEM-encoded public key for RS/ES algorithms.
issuer null When set, the token's iss claim must match.
audience null When set, the token's aud claim must match (string or list).
leeway 30 Seconds of clock skew tolerated on exp/nbf/iat, and when re-checking cached claims.
require_app_claim true Whether a token with no application-binding claim is accepted. A mismatching claim is rejected either way.
claims.user_id sub Which JWT claim is the user id.
claims.user_info user_info Which claim holds optional presence user info.
claims.channels channels Which claim, if present, lists allowed channels (glob patterns).
claims.app_id app_id Which claim carries the application binding.

Claim rules the default validator enforces

Claim Rule
exp Required. A token minted without one is rejected. firebase/php-jwt only validates the value when the claim is present, so accepting a token without it meant accepting a token that never expires.
channels Optional, but if present it must be a list of strings. A non-list ("private-foo", 5, an object, a list with junk in it) is rejected outright rather than coerced.
channels: [] Present but empty is an allow-list that permits nothing, so every private and presence subscribe is denied. Only an absent channels claim means "no token-level restriction".
app_id Required unless require_app_claim is false; must equal the connection's application id.

Plugging in another token format

The default validator is JWT. To accept Sanctum tokens, opaque tokens against an introspection endpoint, or anything else, implement TokenAuthenticator and bind it:

ChannelAuthorizer is the same: bind your own for tenant rules, role checks, or external lookups. TokenClaims::channels() returns null when the token carried no allow-list and a list<string> when it did, so an empty list allows nothing. An authorizer that reads [] as "no restriction" fails open.

A custom TokenAuthenticator must pass exp and the application-binding claim through into TokenClaims::$raw: the plugin reads both from there.

Issuing tokens

A short Laravel helper to mint a JWT this plugin accepts (with firebase/php-jwt):

exp is mandatory, and app_id must match the application the client connects to. Omit channels entirely when the token should not be limited to particular channels; sending it empty denies everything.

Mobile clients fetch this on login and pass it in pusher:subscribe.data.token.

Security notes

Requirements

Testing

The suite does not need Redis or any external service.

License

MIT. See LICENSE.


All versions of resonate-token-auth with dependencies

PHP Build Version
Package Version
Requires php Version ^8.5
firebase/php-jwt Version ^7.0
illuminate/contracts Version ^13.0
illuminate/support Version ^13.0
webpatser/resonate Version ^1.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package webpatser/resonate-token-auth contains the following files

Loading the files please wait ...