PHPackages                             thecolony/colony-login-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. thecolony/colony-login-bundle

ActiveSymfony-bundle[Authentication &amp; Authorization](/categories/authentication)

thecolony/colony-login-bundle
=============================

Symfony bundle for "Log in with the Colony" — a drop-in OIDC login button (controller, routes, Twig helper, pluggable user provisioning) on top of thecolony/oauth2-colony.

v0.2.3(1mo ago)0131↓50%MITPHPPHP &gt;=8.2CI passing

Since Jun 20Pushed 1mo agoCompare

[ Source](https://github.com/TheColonyCC/colony-login-bundle)[ Packagist](https://packagist.org/packages/thecolony/colony-login-bundle)[ RSS](/packages/thecolony-colony-login-bundle/feed)WikiDiscussions main Synced 2w ago

READMEChangelog (4)Dependencies (26)Versions (10)Used By (0)

colony-login-bundle
===================

[](#colony-login-bundle)

[![Packagist Version](https://camo.githubusercontent.com/0610052a54080e8cdbffec57e0aa3cb04b3cd8031d64f3a1c99a7c8f0fb8a091/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f746865636f6c6f6e792f636f6c6f6e792d6c6f67696e2d62756e646c65)](https://packagist.org/packages/thecolony/colony-login-bundle)[![License](https://camo.githubusercontent.com/b54f8e4efc491db446fb984e7d4539bcd690f15278f2381c76ee61378097baa0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f746865636f6c6f6e792f636f6c6f6e792d6c6f67696e2d62756e646c65)](LICENSE)

**"Log in with the Colony" for Symfony — in three steps.**

A thin Symfony bundle over [`thecolony/oauth2-colony`](https://github.com/TheColonyCC/oauth2-colony): it ships the OIDC login controller + routes, a branded `colony_login_button()`Twig helper, and a pluggable user-provisioning interface. You supply how a verified Colony identity maps to *your* user entity; the bundle does the OAuth2/OIDC dance (Authorization Code + PKCE, discovery, nonce, id\_token verification).

Dormant until configured — no client id/secret means the routes 404 and the button hides, so you can ship the bundle before credentials land.

```
composer require thecolony/colony-login-bundle
```

(Pulls in [`thecolony/oauth2-colony`](https://packagist.org/packages/thecolony/oauth2-colony), the framework-agnostic OIDC provider this bundle wraps.)

1. Implement the provisioner
----------------------------

[](#1-implement-the-provisioner)

Map a verified Colony claim set to your application user. Key on `sub` — it is stable; username and email are not.

```
namespace App\Security;

use App\Entity\User;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use TheColony\ColonyLoginBundle\Security\ColonyUserProvisionerInterface;

final class ColonyUserProvisioner implements ColonyUserProvisionerInterface
{
    public function __construct(
        private UserRepository $users,
        private EntityManagerInterface $em,
    ) {}

    public function provision(array $claims): UserInterface
    {
        $sub = (string) $claims['sub'];
        $user = $this->users->findOneBy(['colonySub' => $sub])
            ?? (new User())->setColonySub($sub);
        // ... link by verified email / set profile from $claims as you wish ...
        $this->em->persist($user);
        $this->em->flush();

        return $user;
    }
}
```

2. Configure the bundle
-----------------------

[](#2-configure-the-bundle)

```
# config/packages/colony_login.yaml
colony_login:
    client_id:     '%env(COLONY_CLIENT_ID)%'
    client_secret: '%env(COLONY_CLIENT_SECRET)%'
    provisioner:   App\Security\ColonyUserProvisioner
    authenticator: form_login          # name passed to Security::login()
    cache:         cache.app           # PSR-6 pool; caches discovery + JWKS
    default_uri:   '%env(default::DEFAULT_URI)%'   # canonical origin (optional)
    # optional — enables POST /auth/colony/backchannel-logout (see below):
    backchannel_logout_handler: App\Security\ColonyLogoutHandler
    routes:
        success: app_dashboard
        failure: app_login
    # issuer / scope default to https://thecolony.cc and "openid profile email"
```

```
# config/routes/colony_login.yaml
colony_login:
    resource: '@ColonyLoginBundle/src/Controller/'
    type: attribute
```

This registers `GET /auth/colony` (`colony_login`), `GET /auth/colony/callback`(`colony_login_callback`), `GET /auth/colony/silent` (`colony_login_silent`), and `POST /auth/colony/backchannel-logout` (`colony_login_backchannel`). Register the Colony client's redirect URI as `https:///auth/colony/callback`.

`private_key_jwt` + PAR (optional)
----------------------------------

[](#private_key_jwt--par-optional)

By default the bundle authenticates to the token endpoint with `client_secret`(`client_secret_post`). If your Colony client is registered for **`private_key_jwt`**(RFC 7523) you can drop the shared secret and authenticate with your own signing key instead — and optionally turn on **PAR** (RFC 9126) so the authorization request is pushed server-side:

```
colony_login:
    client_id: '%env(COLONY_CLIENT_ID)%'
    token_endpoint_auth_method: private_key_jwt
    private_key: '%env(COLONY_CLIENT_PRIVATE_KEY)%'   # PEM string, or a path to a PEM file
    private_key_id: key-1                              # optional `kid`
    signing_alg: RS256                                 # RS/PS/ES 256/384/512 (default RS256)
    use_par: true                                      # optional: RFC 9126 PAR
    provisioner: App\Security\ColonyUserProvisioner
    # ... rest as above; client_secret is not needed for private_key_jwt
```

Register the matching **public** key with the Colony for this client. These options pass straight through to `thecolony/oauth2-colony`; the assertion authenticates the token, refresh and PAR requests, and PAR composes with `private_key_jwt`.

Require 2FA (`require_acr`, optional)
-------------------------------------

[](#require-2fa-require_acr-optional)

To force a step-up / MFA login, set `require_acr` (e.g. `mfa`). The bundle sends `acr_values` on the authorization request so the IdP enforces the context up front, then re-checks the returned `id_token`'s `acr`/`amr`:

```
colony_login:
    client_id: '%env(COLONY_CLIENT_ID)%'
    require_acr: mfa                                    # IdP must assert this acr, else the login is rejected
    provisioner: App\Security\ColonyUserProvisioner
    # ... rest as above
```

Passes straight through to `thecolony/oauth2-colony` (&gt;= 0.2.4). The Python counterpart is `require_acr="mfa"` in [`colony-oidc`](https://pypi.org/project/colony-oidc/).

Silent SSO (`prompt=none`)
--------------------------

[](#silent-sso-promptnone)

`GET /auth/colony/silent` starts a no-UI authorization (load it in a hidden iframe) to sign in a user who already has a Colony session. The callback is shared: on `?error=login_required` / `consent_required` it routes to your `failure` route — i.e. your interactive login — which is the correct fallback.

Back-channel logout
-------------------

[](#back-channel-logout)

To end the local session when a user signs out *at the Colony* (even if they never return to your app), implement `ColonyBackchannelLogoutHandlerInterface` and wire it via `backchannel_logout_handler`. That turns on `POST /auth/colony/backchannel-logout`, where the bundle validates the IdP's signed `logout_token` and hands you the claims to terminate sessions for:

```
final class ColonyLogoutHandler implements ColonyBackchannelLogoutHandlerInterface
{
    public function logout(array $claims): void
    {
        // kill local sessions for $claims['sub'] (all of the user's sessions)
        // and/or the single session $claims['sid']. Needs a session store you can
        // query by subject/session id (e.g. a DB session handler with a colony_sub
        // column) — native file sessions can't be looked up this way.
    }
}
```

The endpoint returns `200` once your handler runs, `400` on an invalid token (nobody is logged out), and `404` while no handler is configured. It's a **server-to-server POST with no browser session** — exempt the path from your firewall (allow anonymous) and from CSRF, e.g.:

```
# config/packages/security.yaml — make the back-channel path public
access_control:
    - { path: ^/auth/colony/backchannel-logout$, roles: PUBLIC_ACCESS }
```

3. Add the button
-----------------

[](#3-add-the-button)

The bundle ships a branded, accessible **"Log in with the Colony"** button that matches the PHP and Python SDKs. Drop it in — it points at the login route and **renders nothing while the integration is unconfigured**, so no `{% if %}` guard is needed:

```
{# once, in your  (or serve the CSS yourself): #}
{{ colony_login_styles() }}

{# wherever the button goes: #}
{{ colony_login_button() }}
```

Customise via options — `theme` (`auto` follows the visitor's colour scheme, or `light` / `dark`), `label`, `variant`, `size`, `class`, `attributes`:

```
{{ colony_login_button({ theme: 'dark', label: 'Continue with the Colony', class: 'w-full' }) }}

{# point at a different route, or an explicit URL: #}
{{ colony_login_button({ route: 'colony_login_silent' }) }}
{{ colony_login_button({ href: url('colony_login') }) }}
```

The mark inside defaults to `currentColor`, so it follows the button's text on light and dark themes. Other Twig helpers: `colony_login_enabled()` (the boolean, if you want your own markup) and `colony_mark('cyan', 32)` (just the mark as inline SVG). All button/mark markup comes from `TheColony\OAuth2\ColonyBrand`(see its `BRANDING.md` for variant guidance and approved copy).

Prefer your own button? The old form still works:

```
{% if colony_login_enabled() %}
    Log in with the Colony
{% endif %}
```

That's it. On callback the bundle verifies the id\_token (signature + claims), calls your provisioner, and logs the returned user in via Symfony's security system.

Why `default_uri`?
------------------

[](#why-default_uri)

If your app is reachable on more than one host (e.g. `www.` and the apex), the OAuth `redirect_uri` must always match the one registered with the client *and*the session holding `state`/`nonce`/PKCE must survive the round-trip. Set `default_uri` to your canonical origin and the flow is pinned there — the start route bounces any other host to the canonical one first.

What lives where
----------------

[](#what-lives-where)

ConcernPackageOAuth2/OIDC protocol (discovery, PKCE, id\_token + JWKS verify)[`thecolony/oauth2-colony`](https://github.com/TheColonyCC/oauth2-colony)Symfony glue (controller, routes, Twig, DI, provisioning seam)this bundleYour user model + linking policyyour app (the provisioner)Development
-----------

[](#development)

```
composer update
vendor/bin/phpunit
```

Unit tests cover the DI wiring and every controller branch except the final `Security::login()` success call, which is exercised end-to-end by the reference integration (Progenly) rather than reconstructed in isolation.

License
-------

[](#license)

MIT © The Colony

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance92

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 92.9% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

8

Last Release

41d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/271974769?v=4)[Colin Easton](/maintainers/ColonistOne)[@ColonistOne](https://github.com/ColonistOne)

---

Top Contributors

[![ColonistOne](https://avatars.githubusercontent.com/u/271974769?v=4)](https://github.com/ColonistOne "ColonistOne (13 commits)")[![jackparnell](https://avatars.githubusercontent.com/u/2689600?v=4)](https://github.com/jackparnell "jackparnell (1 commits)")

---

Tags

symfonybundleSSOoauth2loginOpenID Connectoidcthecolonycolony

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/thecolony-colony-login-bundle/health.svg)

```
[![Health](https://phpackages.com/badges/thecolony-colony-login-bundle/health.svg)](https://phpackages.com/packages/thecolony-colony-login-bundle)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k18.3M414](/packages/easycorp-easyadmin-bundle)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k6.0M763](/packages/sylius-sylius)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M222](/packages/sulu-sulu)[pimcore/pimcore

Content &amp; Product Management Framework (CMS/PIM/E-Commerce)

3.8k3.9M530](/packages/pimcore-pimcore)[symfony/security-bundle

Provides a tight integration of the Security component into the Symfony full-stack framework

2.5k190.0M2.5k](/packages/symfony-security-bundle)[shopware/storefront

Storefront for Shopware

684.7M270](/packages/shopware-storefront)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
