ruwork/runet-id-bundle
Symfony bundle for integrating Runet ID authentication into your application. It provides configuration and services to connect Runet ID accounts with Symfony security, enabling single sign-on and streamlined user login flows.
ruwork/runet-id-bundle is an archived (last release 2018-08-20, zero stars, zero dependents) Symfony bundle that wires the RU-CENTER RUNET-ID OAuth-style identity service into a Symfony app, so Russian users can sign in with their RUNET-ID account. Treat it as reference code you are adopting, not a maintained dependency.
Minimal steps:
composer require ruwork/runet-id-bundle succeeds. Inspect composer.json in the repo before installing.AppKernel:
// app/AppKernel.php
$bundles[] = new Ruwork\RunetIdBundle\RuworkRunetIdBundle();
On Symfony 4+ it ships with a DependencyInjection/RuworkRunetIdExtension and should be auto-registered via Flex; check config/bundles.php.config/packages/ruwork_runet_id.yaml (or app/config/config.yml). You need a client_id/client_secret pair issued by RU-CENTER for your RUNET-ID application, plus a redirect URI registered with them:
ruwork_runet_id:
client_id: '%env(RUNET_ID_CLIENT_ID)%'
client_secret: '%env(RUNET_ID_CLIENT_SECRET)%'
redirect_uri: '%env(RUNET_ID_REDIRECT_URI)%'
DependencyInjection/Configuration.php (authoritative list of every config key), Resources/config/services.xml (the service ids you can autowire or override), and any Security/ directory (the authenticator/user provider you will plug into security.yaml).OAuth redirect + callback controller. The idiomatic flow is:
GET /login/runet-id → controller asks the bundle's client for the authorization URL (with a state value you generate and stash in the session) and returns a RedirectResponse.GET /login/runet-id/check → controller validates state, exchanges code for a token, calls the profile endpoint, then hands the profile to your UserProvider and logs the user in.Keep the two actions in a dedicated RunetIdController rather than mixing them into your main security controller.
User provider / user factory. RUNET-ID gives you a profile record (typically an internal id, email, display name, and possibly a verified flag). Write a small RunetIdUserProvider (or a user factory service) that maps that profile onto your App\Entity\User:
public function loadUserFromProfile(array $profile): User
{
$user = $this->users->findOneBy(['runetId' => $profile['id']])
?? new User();
$user->setRunetId($profile['id']);
$user->setEmail($profile['email'] ?? $user->getEmail());
$user->setDisplayName($profile['name'] ?? $user->getDisplayName());
return $user;
}
Always persist a stable runetId column; never key on email alone, since RUNET-ID profiles can change email.
security.yaml integration. Either register the bundle's guard authenticator, or — more future-proof — write a tiny custom authenticator/factory (AbstractGuardAuthenticator on 4.x, AbstractAuthenticator on 5.4+) that wraps the RUNET-ID client. Wrapping is preferable because it insulates your app from the archived bundle's API if you later swap it out.
Profile refresh, not just login. If you store the RUNET-ID access token, you can periodically call the profile endpoint to pick up name/avatar changes. Do this lazily (on next login) rather than in a cron to keep scope small.
Local development. RUNET-ID requires an externally reachable redirect URI. Use a tunnel (ngrok, symfony serve + tunnel, or a staging subdomain) and register each URI in the RUNET-ID application settings — the service will reject unregistered URIs.
Testing. Abstract the client behind a thin interface (RunetIdClientInterface::getProfile(string $accessToken): array) and mock it in tests. The bundle itself has no test suite, so your own contract tests are the only safety net.
"replace" or a VCS repository entry in composer.json, and pin the fork. Do not rely on a transient dependency resolving it transitively.DependencyInjection/Configuration.php — Symfony silently ignores unknown keys only after Flex validation; many 2018-era bundles used non-standard key names.redirect_uri_mismatch), expired/invalid state, or a client_secret with a trailing newline from .env.state is your job. If the bundle doesn't implement CSRF-style state validation, add it. It's a two-line session write/read but it prevents login CSRF.SameSite. Modern browser defaults (SameSite=Lax) can drop the session cookie on the cross-site redirect back from RUNET-ID. If the callback logs the user out, set framework.session.cookie_samesite: null (or use a state-signed stateless flow) before blaming the bundle.sodium_crypto_secretbox with a key in your secrets store); the bundle predates Symfony's SecretsVault and gives you no storage strategy.Resources/config/services.xml. Override a service by redeclaring the same id in your app's services.yaml (with the alias set to public if the bundle kept it private) rather than forking, for small behavioral tweaks.How can I help you explore Laravel packages today?