Installation
composer require hwi/oauth-bundle
Add to config/bundles.php:
return [
// ...
HWI\Bundle\OAuthBundle\HWIOAuthBundle::class => ['all' => true],
];
Configure Providers
Edit config/packages/hwi_oauth.yaml (or create it):
hwi_oauth:
connect:
account_connector: your_app.user.provider.oauth # Custom service
# Example for GitHub:
github:
skip_if_logged_in: true
client_id: "your_client_id"
client_secret: "your_client_secret"
scope: "read:user user:email"
First Use Case: Login with GitHub
config/routes.yaml:
hwi_oauth_connect:
resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
prefix: /connect
<a href="{{ path('hwi_oauth_connect_github') }}">Login with GitHub</a>
/connect/github (or other provider).email, name) from the provider.account_connector service to map provider data to your User entity:
// src/User/OAuthUserProvider.php
namespace App\User;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use Symfony\Component\Security\Core\User\UserInterface;
class OAuthUserProvider implements \HWI\Bundle\OAuthBundle\Connect\AccountConnectorInterface
{
public function connect(UserResponseInterface $response, $accountLifetime = null)
{
$user = new YourUser();
$user->setEmail($response->getEmail());
$user->setUsername($response->getUsername());
$user->addRole('ROLE_USER');
return $user;
}
}
skip_if_logged_in to prevent logged-in users from re-authenticating.email instead of user).hwi_oauth.yaml:
github: { ... }
google: { ... }
routing.yaml:
hwi_oauth_connect:
path: /login/oauth/{provider}
account_connector:
$response->getEmail();
$response->getFirstName();
$response->getLastName();
$response->getAccessToken(); // For API calls later
User entity for future API requests:
$user->setAccessToken($response->getAccessToken());
Missing account_connector
Forgetting to configure account_connector will throw:
No account connector found for provider "github".
Fix: Define the service in services.yaml:
services:
your_app.user.provider.oauth:
class: App\User\OAuthUserProvider
tags:
- { name: hwi_oauth.connect.account_connector, connector: github }
CORS Issues with API Calls If using the access token to call provider APIs, ensure:
Token Expiry
OAuth2 tokens expire. Implement token refresh logic in your account_connector or a separate service:
if ($user->getAccessTokenExpiresAt() < new \DateTime()) {
$newToken = $this->refreshToken($user->getRefreshToken());
$user->setAccessToken($newToken);
}
Provider-Specific Quirks
user:email scope for email access.fb as the route prefix by default (not facebook).debug: true in hwi_oauth.yaml to log OAuth responses:
hwi_oauth:
debug: true
var/log/dev.log (Symfony) or storage/logs/laravel.log (Laravel).
Example error:
Client error: `GET https://api.github.com/user` resulted in a `401 Unauthorized` response
Fix: Verify client_id, client_secret, and scopes.Custom User Entity
Extend the User entity to include OAuth-specific fields:
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $oauthProvider;
private $oauthProviderId;
private $accessToken;
private $accessTokenExpiresAt;
Post-Auth Redirects
Use Symfony’s security.authentication.success_handler to redirect users after login:
# config/packages/security.yaml
security:
firewalls:
main:
form_login:
success_handler: App\Security\OAuthSuccessHandler
// src/Security/OAuthSuccessHandler.php
public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
$targetUrl = $this->determineTargetUrl($request);
return new RedirectResponse($targetUrl);
}
API Client Integration Use the stored access token to call provider APIs:
$client = new \GuzzleHttp\Client();
$response = $client->get('https://api.github.com/user/repos', [
'auth' => [$user->getEmail(), $user->getAccessToken()],
]);
Dynamic Provider Configuration Load provider configs from a database or environment variables:
# .env
GITHUB_CLIENT_ID=your_id
GITHUB_CLIENT_SECRET=your_secret
// In a service
$config = [
'github' => [
'client_id' => $_ENV['GITHUB_CLIENT_ID'],
'client_secret' => $_ENV['GITHUB_CLIENT_SECRET'],
],
];
User entity or Redis.User entity getter).How can I help you explore Laravel packages today?