wikimedia/toolforge-bundle
Symfony bundle for running applications on Wikimedia Toolforge. Provides ready-made integration with Toolforge services like MySQL, Redis, and Kubernetes, plus configuration helpers that simplify deploying and operating Symfony apps on the platform.
Reality check first: wikimedia/toolforge-bundle is a Symfony 4/5 bundle, not a Laravel package. There is no service provider, no facade, no config publish tag. composer require in a Laravel app will install the code but you cannot boot it — it depends on Symfony\Component\HttpKernel\Bundle\Bundle, the Symfony DI container, the Security component, and Twig bundle conventions. For a Laravel developer, day-to-day leverage comes in one of two forms:
Minimal steps (Symfony path):
composer require wikimedia/toolforge-bundle
config/bundles.php (Symfony 4/5 Flex) or AppKernel.php.https://meta.wikimedia.org/wiki/Special:OAuthConsumerRegistration) — you need the consumer key/secret and an exact callback URL. Do this before writing config; nothing works without it.src/DependencyInjection/Configuration.php in the version you installed, since they have churned between releases.user_class config at it and run a Doctrine migration.Where to look first, in order:
README.md — the only real documentation; expect it to be short.src/DependencyInjection/Configuration.php — the authoritative list of config keys. README drift is common here.src/Security/ — user provider, authenticator, and the ToolforgeUser/ToolforgeUserInterface contract.src/EventSubscriber/ — how the current user is attached to the request.Resources/config/ — service definitions, so you know what to decorate rather than fork.composer.json — confirms which Symfony majors and which OAuth client (mediawiki/oauthclient for 1.0a, or an OAuth2 client) you actually got.First use case to ship: a single protected route that logs a user in via Wikimedia and renders their username plus global groups in Twig. That exercises config, the OAuth callback, the user provider, session persistence, and the Twig integration in one pass — and it's exactly the shape 90% of Toolforge tools need.
Gate a controller on Wikimedia identity. Don't hand-roll session checks; let the Security component do it and read the user from the token:
#[Route('/dashboard', name: 'dashboard')]
public function dashboard(): Response
{
$user = $this->getUser(); // ToolforgeUserInterface
return $this->render('dashboard.html.twig', [
'username' => $user->getUsername(),
'groups' => $user->getGlobalGroups(),
]);
}
Authorize on CentralAuth groups, not local roles. This is the pattern that makes the bundle worth using. Toolforge tools typically gate admin actions on Wikimedia global groups (sysop, global-sysop, steward, accountcreator) rather than maintaining a local role table:
$isSysop = in_array('sysop', $user->getGlobalGroups(), true);
Wrap this in a Symfony voter (ToolforgeGroupVoter) so templates and controllers share one rule instead of scattering in_array calls.
Subclass the user entity for app-specific data. The bundle gives you the Wikimedia identity; it does not give you your app's data model. Extend the provided user class (or implement its interface), join your own tables to it, and let the bundle's provider hydrate the Wikimedia half. This keeps a clean split: bundle owns identity, you own application state.
Keep secrets in env, never in toolforge.yaml. Toolforge deploys are typically git-checkout-based, and the OAuth consumer secret is the whole ballgame:
# config/packages/toolforge.yaml
toolforge:
oauth:
consumer_key: '%env(WIKIMEDIA_OAUTH_KEY)%'
consumer_secret: '%env(WIKIMEDIA_OAUTH_SECRET)%'
user_class: App\Entity\User
Handle anonymous gracefully. Toolforge tools are usually public-read/write-authenticated. Don't force the OAuth dance on every visitor — leave the firewall lazy/anonymous and only challenge on the write actions.
For the Laravel port, use this bundle's structure as the spec. The three moving parts map cleanly:
// config/services.php
'wikimedia' => [
'client_id' => env('WIKIMEDIA_OAUTH_KEY'),
'client_secret' => env('WIKIMEDIA_OAUTH_SECRET'),
'redirect' => env('WIKIMEDIA_REDIRECT_URI'),
],
Then a Socialite provider hitting the MediaWiki REST endpoints (/w/rest.php/oauth2/authorize, /w/rest.php/oauth2/access_token, /w/rest.php/oauth2/resource/profile on meta.wikimedia.org), a WikimediaIdentity value object mirroring ToolforgeUser, and a EnsureWikimediaUser middleware. Store the access token on the user row — you'll need it to call the Action API on the user's behalf. If your installed bundle version targets OAuth 1.0a instead, that's a different signing story; decide up front which protocol your tool needs.
Testing. In Symfony, mock the user provider or inject a test ToolforgeUser into the token storage. In a Laravel port, Socialite::shouldReceive('driver->user') gives you the same isolation. Either way, never let tests reach Meta-Wiki.
src/ for anything beyond the happy path, and pin an exact version — there is no ecosystem to catch regressions for you.https://<tool>.toolforge.org/; a mismatch produces an opaque rejection on Meta-Wiki that looks like a bundle bug but isn't.trusted_proxies and framework.trusted_hosts so Symfony sees the real scheme and host; otherwise generated callback URLs silently come out as http:// and the OAuth round-trip fails.cookie_domain/cookie_secure setting. Multiple tools on *.toolforge.org sharing a cookie name will clobber each other.bin/console debug:router, debug:container --tag=security.authenticator, debug:event-dispatcher security.*, and var/log/dev.log. If login loops, it's almost always session persistence or a trusted-proxy issue, not the OAuth exchange.user_class config, a decorating service over the user provider, a security voter for group rules, and Twig template overrides in templates/bundles/ToolforgeBundle/. Forking a 15-star GPL bundle is a maintenance trap.Configuration.php is the truth.How can I help you explore Laravel packages today?