Repository navigation
v1.6.74 — Webhook endpoints for API keys, signed per endpoint, safer upload names, App Review access, and Sign in with Fleetbase
Added
- Webhook endpoints can be managed with an API key (#319).
/v1/webhook-endpointssupports create, list (optionally filtered byurl), show, update,POST {id}/rotate-secretand delete. Endpoints are scoped to the key's company and environment (live/test). The URL must passPublicWebhookUrl, and events are checked againstconfig('api.events')when it is set. Integrations such as WooCommerce and Shopify connectors can now register their own endpoints instead of merchants copying URLs into the console. - Per-endpoint signing secrets (#319). Each endpoint has its own secret (
whsec_…), stored encrypted, hidden from serialisation and kept out of the activity log. Endpoints that already exist get one the first time it is needed. Deliveries now also carryX-Fleetbase-Signature: t=<unix>,v1=<hmac_sha256("<t>.<body>", secret)>;EndpointSignature::verify()documents the receiver side. The legacySignatureheader is unchanged. The console can reveal (GET int/v1/webhook-endpoints/{id}/secret, view permission) and rotate (POST int/v1/webhook-endpoints/{id}/rotate-secret, create permission) the secret. - App Review access (#323). Apple and Google reviewers can't receive a texted sign-in code. Extensions register what their app signs reviewers in to (
Fleetbase\Support\AppReview::register(), e.g. a Storefront store or an organization's Navigator app) with a review number from the 555-0100–0199 range reserved for fiction. Owners turn access on in the Console (GET|PUT int/v1/review-access/{type}/{id}) and give the app store that number and a six-digit code, stored hashed, shown once, and accepted only for that subject. Works on Fleetbase Cloud and self-hosted.AppReview::configuredAccountMatches()is the shared env fallback for self-hosted review accounts. - Sign in with Fleetbase, an OAuth 2.0 / OpenID Connect provider (#324). Registered apps can offer "Continue with Fleetbase" and, with the user's consent, act on one organization they administer. Built on league/oauth2-server.
- Authorization code flow with PKCE (
S256) required for every client, rotating refresh tokens, RFC 7009 revocation, ID tokens,/oauth/userinfo,/oauth/jwksand/.well-known/openid-configuration. - The consent screen runs in the console, so the console's sign-in and two-factor rules apply. Endpoints:
int/v1/oauth-server/authorization(GET, POST, DELETE). - Each consent is an
oauth_grantsrow bound to the organization the user picked. Every refresh and every API call checks that the user is still active and still administers that organization. - Scopes:
openid,profile,emailandorganization:read(GET /oauth/v1/organization). Extensions register their own scopes withFleetbase\Auth\OAuthServer\OAuthScopes::register(), optionally covering App Review types served by/oauth/v1/review-access/{type}/{id}. - Replayed codes revoke their tokens; a replayed refresh token revokes the whole grant.
- System admins register apps, rotate secrets, turn apps off and revoke grants (
int/v1/oauth-server/apps). Users list and remove their connected apps (int/v1/oauth-server/connected-apps) and get an email when they authorize a new one. - Artisan:
oauth-server:keys,oauth-server:client create|rotate|list,oauth-server:prune(scheduled daily).
- Authorization code flow with PKCE (
- Dynamic client registration for software installed on many sites (RFC 7591). A plugin on a merchant's own domain cannot share one registered redirect URI, so each install registers its own public PKCE client at
POST /oauth/register(throttled, advertised asregistration_endpointin discovery). Only software listed underoauth-server.registration.softwarecan register, with the scopes listed there; today that isfleetbase-woocommerce(organization:read,api-key:create). Each client has exactly one redirect URI (https, or http on loopback as a development client), is never official, and is named after its host, e.g. "Fleetbase for WooCommerce (shop.example.com)", which is what the consent screen and Connected apps show. Registering again returns the same client; clients that never get a grant are pruned after a day.OAUTH_SERVER_REGISTRATION_ENABLED=falseturns it off. api-key:createscope andPOST /oauth/v1/api-key. Creates a live API key named after the app in the token's organization, or returns the one that app created before (tracked by the newapi_credentials.oauth_client_id, never by name). The key is listed under Developers → API Keys. When the app's last grant in that organization is revoked (Connected apps, an admin revoking it, or the app being turned off), the key expires. This lets an integration such as Fleetbase for WooCommerce connect without anyone pasting a key. An app that serves many installations from one client (the Shopify app, one per shop) passesinstallationand gets a key per installation, named "{app} ({installation})" and tracked byapi_credentials.oauth_installation.DELETE /oauth/v1/api-key(same scope, same optionalinstallation) expires one installation's key without touching the grant or other installations.
Security
- Numbers reserved for fiction are never texted (#323).
SmsService::send()answers as sent without calling a provider, and SMS verification codes for those numbers are saved but not sent. - Uploaded files are stored under an extension that matches their contents (#320). The stored name used to keep the client's extension, so a file that passed content-type validation could be stored as
.php. The client's extension is now kept only when it matches the detected type (or is a loosely detected data format such ascsv,jsonorxlsx); otherwise the extension comes from the detected type. Script extensions (php,phtml,phar,shtml,htaccess,cgi, …) are never used and becomebin.original_filenameis unchanged. - OAuth provider hardening (#324). OAuth client secrets are stored only as bcrypt hashes and shown once. Redirect URIs match exactly, and errors about an unknown client or unregistered redirect URI are never redirected. OAuth rows always use the core database connection, even when the console is in sandbox mode.
Upgrade Steps
- Run migrations:
php artisan migrateadds the nullablewebhook_endpoints.secretcolumn, thereview_accessestable, theoauth_*provider tables (oauth_clients,oauth_grants,oauth_auth_codes,oauth_access_tokens,oauth_refresh_tokens),oauth_clients.software_idandregistration_key, andapi_credentials.oauth_client_idandoauth_installation. - To use Sign in with Fleetbase, give every API instance the same signing key pair:
php artisan oauth-server:keys(key files instorage/), orphp artisan oauth-server:keys --showand setOAUTH_SERVER_PRIVATE_KEY/OAUTH_SERVER_PUBLIC_KEY. SetOAUTH_SERVER_ISSUERif the public API URL differs fromAPP_URL. New dependencies:league/oauth2-server,nyholm/psr7,symfony/psr-http-message-bridge. - The consent screen, Admin → Auth Config → OAuth Apps and Account → Auth → Connected apps ship in the console (fleetbase/fleetbase#734). Storefront's
storefront:*scopes ship in fleetbase/storefront#163.
What's Changed
- feat(webhooks): API-key webhook endpoints and per-endpoint signing secrets by @roncodes in #319
- Derive uploaded file extension from the validated MIME type by @shivanathd in #320
- feat(app-review): App Review access for apps built on Fleetbase by @roncodes in #323
- feat(oauth-server): Sign in with Fleetbase (OAuth 2.0 / OpenID Connect provider) by @roncodes in #324
- feat(routing): Fleetbase Hosted Routing keys at install time by @roncodes in #325
- fix(oauth-server): /oauth/authorize fatal error by @roncodes in #326
- feat(oauth-server): dynamic client registration and the api-key:create scope by @roncodes in #327
- v1.6.74 by @roncodes in #322
New Contributors
- @shivanathd made their first contribution in #320
Full Changelog: v1.6.73...v1.6.74