## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require craffft/contao-discourse "~2.0"
Ensure your project uses Contao 4.x and Symfony 4.x/5.x (as the bundle is built for Contao’s Symfony integration).
Enable the Bundle:
Add the bundle to config/bundles.php (Symfony 4+) or app/AppKernel.php (Symfony 3/Contao 3):
return [
// ...
Craffft\ContaoDiscourseSSOBundle\CraffftContaoDiscourseSSOBundle::class => ['all' => true],
];
Configuration:
Publish the default config and update config/packages/craffft_contao_discourse.yaml:
php bin/console contao:discourse:install
This generates a discourse.yaml file in config/packages/. Configure:
discourse_url: Your Discourse instance URL (e.g., https://forum.example.com).secret_key: Shared secret from Discourse admin → Settings → Single Sign On.trust_proxy: Set to true if behind a reverse proxy (e.g., Nginx/Apache).First Use Case: Test SSO by logging into Contao and clicking a "Discourse SSO" link (if added to a module). Verify redirection to Discourse and automatic login.
User Authentication Flow:
DiscourseSsoService:
use Craffft\ContaoDiscourseSSOBundle\Service\DiscourseSsoService;
$ssoService = $this->container->get(DiscourseSsoService::class);
$ssoUrl = $ssoService->generateSsoUrl($contaoUserId, $contaoUserEmail);
Redirect users to $ssoUrl (Discourse will handle authentication).sso query param. Override the ContaoUserListener to sync Discourse users to Contao:
# config/packages/craffft_contao_discourse.yaml
craffft_contao_discourse:
sync_users: true # Auto-create Contao users on SSO
User Synchronization:
php bin/console contao:discourse:sync-users
UserSynchronizer to customize field mappings (e.g., map Discourse username to Contao username):
// src/EventListener/CustomUserSynchronizer.php
public function syncUser($discourseUser, ContaoUser $contaoUser)
{
$contaoUser->username = $discourseUser['username'];
$contaoUser->save();
}
Register the listener in services.yaml:
services:
App\EventListener\CustomUserSynchronizer:
tags: ['contao.discourse.user_synchronizer']
Role Mapping:
craffft_contao_discourse:
group_mapping:
admins: ['admin'] # Discourse group "admins" → Contao group "admin"
moderators: ['moderator'] # Discourse group "moderators" → Contao group "moderator"
// src/Resources/contao/dca/tl_module.php
$GLOBALS['TL_DCA']['tl_module']['palettes']['discourse_sso'] .= ';discourse_sso';
$GLOBALS['TL_DCA']['tl_module']['fields']['discourse_sso'] = [
'label' => ['Discourse SSO', 'discourse_sso'],
'inputType' => 'button',
'eval' => ['button_callback' => ['ContaoDiscourse', 'generateSsoUrl']],
];
{# templates/mod_discourse_sso.html #}
<a href="{{ path('contao_discourse_sso', {'userId': member.id}) }}">Go to Discourse</a>
Route the link in config/routes.yaml:
contao_discourse_sso:
path: /discourse/sso/{userId}
controller: Craffft\ContaoDiscourseSSOBundle\Controller\SsoController::generateSsoUrl
Secret Key Mismatch:
config/packages/craffft_contao_discourse.yaml.User Sync Conflicts:
sync_users: false) and manually sync via CLI:
php bin/console contao:discourse:sync-users --force
Use --dry-run to preview changes:
php bin/console contao:discourse:sync-users --dry-run
CORS Issues:
sso_secret and sso_url are correctly configured, and Contao’s trust_proxy is set if behind a proxy.Contao User Group Permissions:
group_mapping to include Contao’s admin group.Enable Debug Logging:
Add to config/packages/craffft_contao_discourse.yaml:
craffft_contao_discourse:
debug: true
Logs appear in var/log/contao_discourse.log.
Test SSO Locally:
Use ngrok to expose Discourse locally for testing:
ngrok http 3000 # If Discourse runs on port 3000
Update discourse_url to your ngrok.io subdomain.
Custom User Fields:
Extend the UserSynchronizer to map custom Discourse fields (e.g., custom_fields) to Contao user fields:
public function syncUser($discourseUser, ContaoUser $contaoUser)
{
if (isset($discourseUser['custom_fields']['location'])) {
$contaoUser->address = $discourseUser['custom_fields']['location'];
}
}
Pre-SSO Hooks: Add logic before SSO (e.g., validate user eligibility):
// src/EventListener/PreSsoListener.php
public function onPreSso(PreSsoEvent $event)
{
if (!$event->getUser()->isActive) {
throw new \RuntimeException('User is inactive.');
}
}
Register the listener:
services:
App\EventListener\PreSsoListener:
tags: ['kernel.event_listener', 'contao_discourse.pre_sso']
Post-Sync Actions: Trigger actions after user sync (e.g., send welcome email):
// src/EventListener/PostSyncListener.php
public function onPostSync(PostSyncEvent $event)
{
$this->mailer->sendWelcomeEmail($event->getContaoUser());
}
Register:
services:
App\EventListener\PostSyncListener:
tags: ['kernel.event_listener', 'contao_discourse.post_sync']
group_mapping are case-sensitive. Use the exact group name from Discourse’s API (/admin/groups.json).UserSynchronizer:
$contaoUser->email = strtolower(trim($discourseUser['email']));
How can I help you explore Laravel packages today?