hwi/oauth-bundle
Symfony bundle for OAuth1.0a/OAuth2 login and user authentication. Supports Symfony 6.4–8.0 (PHP 8.3+) and integrates dozens of providers (Google, GitHub, Facebook, Apple, LinkedIn, Azure, Keycloak, etc.).
Install the Bundle
composer require hwi/oauth-bundle
Configure a Resource Owner (config/packages/hwi_oauth.yaml):
hwi_oauth:
resource_owners:
google:
type: google
client_id: "%env(GOOGLE_CLIENT_ID)%"
client_secret: "%env(GOOGLE_CLIENT_SECRET)%"
scope: "email profile openid"
Enable the Route (config/routes.yaml):
hwi_oauth_connect:
resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /login
Create a Security Firewall (config/packages/security.yaml):
firewalls:
main:
oauth:
resource_owners:
google: "/login/check-google"
login_path: /login
failure_path: /login
oauth_user_provider:
service: hwi_oauth.user.provider
First Use Case: Login Button
Add a link to /login/check-google in your template. After successful OAuth, the user is authenticated and redirected to the configured default_target_path.
Configure multiple providers in hwi_oauth.yaml and expose them in the firewall:
firewalls:
main:
oauth:
resource_owners:
google: "/login/check-google"
github: "/login/check-github"
Extend HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUserProvider to map OAuth data to your User entity:
// src/Security/OAuthUserProvider.php
use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthUserProvider as BaseOAuthUserProvider;
class OAuthUserProvider extends BaseOAuthUserProvider
{
public function connect(UserInterface $user, UserProviderInterface $userProvider, $accountIdentifier)
{
// Custom logic to link OAuth accounts to your User entity
}
public function loadUserByOAuthUserClass($class)
{
return new YourUserEntity();
}
}
Register the service in config/services.yaml:
services:
App\Security\OAuthUserProvider:
arguments:
- '@fos_user.user_manager' # or your user manager
- '@hwi_oauth.security.oauth_utils'
tags:
- { name: hwi_oauth.user.provider }
For providers supporting token refresh (e.g., Google), implement a service to refresh tokens:
// src/Service/OAuthTokenRefresher.php
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
class OAuthTokenRefresher
{
public function refreshToken(UserResponseInterface $response)
{
$client = $response->getOAuthWebService()->getClient();
$client->refreshToken($response->getAccessToken());
return $client->getAccessToken();
}
}
Use placeholders or environment variables for scopes to avoid hardcoding:
hwi_oauth:
resource_owners:
github:
scope: "user:email repo %env(GITHUB_SCOPE_EXTRA)%"
Use the hwi_oauth.on.connect event to trigger actions after login:
// src/EventListener/OAuthConnectListener.php
use HWI\Bundle\OAuthBundle\Event\ConnectEvent;
class OAuthConnectListener
{
public function onConnect(ConnectEvent $event)
{
$user = $event->getUser();
// Example: Sync user data or log the event
}
}
Register the listener in config/services.yaml:
services:
App\EventListener\OAuthConnectListener:
tags:
- { name: kernel.event_listener, event: hwi_oauth.on.connect, method: onConnect }
%env() for client_id and client_secret to avoid exposing secrets in config files.base_url is correctly set (e.g., https://your-jira-instance.com).redirect_uri in your OAuth provider settings matches the one configured in Symfony (default: http://localhost:8000/connect/{resource_owner}/check).state parameter is included in the request.access_token expiry gracefully.$response = $this->get('hwi_oauth.user.provider')->loadUserByOAuthUserResponse($response);
// Cache $response->getAccessToken() and user data if needed
templates/HWIOAuthBundle/:
{# templates/HWIOAuthBundle/Connect/connect.html.twig #}
{% extends '@HWIOAuth/Connect/connect.html.twig' %}
{% block title %}Custom OAuth Login{% endblock %}
hwi_oauth:
http_client:
timeout: 15
state parameter in OAuth flows to prevent CSRF attacks.access_token and refresh_token securely (e.g., encrypted in the database).client_id/client_secret handling.hwi_oauth.on.connect event to ensure post-login logic works as expected.hwi_oauth.firewall_name in favor of firewall-specific settings).How can I help you explore Laravel packages today?