-
-
Save Mouerr/b0f770c80cc5abaacb0969321607c60d to your computer and use it in GitHub Desktop.
Symfony OAuth with Leage OAuth2 library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<a href="{{ googleAuthorizationUrl }}"> | |
Login | |
</a> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App; | |
use Symfony\Component\HttpFoundation\Response; | |
use Twig\Environment; | |
use League\OAuth2\Client\Provider\Google as GoogleProvider; | |
final class Login | |
{ | |
/** | |
* @var Environment | |
*/ | |
private $twig; | |
/** | |
* @var GoogleProvider | |
*/ | |
private $provider; | |
public function __construct(Environment $twig, GoogleProvider $provider) | |
{ | |
$this->twig = $twig; | |
$this->provider = $provider; | |
} | |
public function __invoke(): Response | |
{ | |
return new Response($this->twig->render( | |
'login.html.twig', | |
[ | |
'googleAuthorizationUrl' => $this->provider->getAuthorizationUrl(), | |
] | |
)); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App; | |
use League\OAuth2\Client\Provider\Google as GoogleProvider; | |
use League\OAuth2\Client\Provider\GoogleUser; | |
use League\OAuth2\Client\Token\AccessTokenInterface; | |
use Symfony\Component\HttpFoundation\RedirectResponse; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Session\SessionInterface; | |
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | |
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | |
use Symfony\Component\Security\Core\Exception\AuthenticationException; | |
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; | |
use Symfony\Component\Security\Core\Security; | |
use Symfony\Component\Security\Core\User\UserInterface; | |
use Symfony\Component\Security\Core\User\UserProviderInterface; | |
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; | |
final class OAuthAuthenticator extends AbstractGuardAuthenticator | |
{ | |
private const ROUTE_LOGIN = 'auth.login'; | |
private const ROUTE_OAUTH_LOGIN = 'auth.connect.google'; | |
private const ROUTE_DASHBOARD = 'index'; | |
/** | |
* @var GoogleProvider | |
*/ | |
private $provider; | |
/** | |
* @var UrlGeneratorInterface | |
*/ | |
private $urlGenerator; | |
public function __construct(GoogleProvider $provider, UrlGeneratorInterface $urlGenerator) | |
{ | |
$this->provider = $provider; | |
$this->urlGenerator = $urlGenerator; | |
} | |
public function start(Request $request, AuthenticationException $authException = null): RedirectResponse | |
{ | |
return new RedirectResponse( | |
$this->urlGenerator->generate(self::ROUTE_LOGIN) | |
); | |
} | |
public function supports(Request $request): bool | |
{ | |
return $request->attributes->get('_route') === self::ROUTE_OAUTH_LOGIN; | |
} | |
public function getCredentials(Request $request): AccessTokenInterface | |
{ | |
if (!$request->query->has('code')) { | |
throw new CustomUserMessageAuthenticationException('Missing code.'); | |
} | |
return $this->provider->getAccessToken('authorization_code', [ | |
'code' => $request->query->get('code') | |
]); | |
} | |
public function getUser($credentials, UserProviderInterface $userProvider): UserInterface | |
{ | |
$googleUser = $this->provider->getResourceOwner($credentials); | |
\assert($googleUser instanceof GoogleUser); | |
try { | |
$email = $googleUser->getEmail(); | |
\assert(\is_string($email)); | |
return $userProvider->loadUserByUsername($email); | |
} catch (UserDoesNotExist $exception) { | |
throw new CustomUserMessageAuthenticationException($exception->getMessage()); | |
} | |
} | |
public function checkCredentials($credentials, UserInterface $user): bool | |
{ | |
return true; | |
} | |
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): RedirectResponse | |
{ | |
$session = $request->getSession(); | |
\assert($session instanceof SessionInterface); | |
$session->set(Security::AUTHENTICATION_ERROR, $exception); | |
return new RedirectResponse( | |
$this->urlGenerator->generate(self::ROUTE_LOGIN) | |
); | |
} | |
public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey): RedirectResponse | |
{ | |
return new RedirectResponse( | |
$this->urlGenerator->generate(self::ROUTE_DASHBOARD) | |
); | |
} | |
public function supportsRememberMe(): bool | |
{ | |
return true; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
auth.login: | |
path: /login | |
controller: App\Login | |
methods: [GET] | |
auth.logout: | |
path: /logout | |
methods: [GET] | |
auth.connect.google: | |
path: /connect/google | |
methods: [GET] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
security: | |
providers: | |
users: | |
id: App\UserProvider | |
firewalls: | |
login: | |
pattern: /login | |
anonymous: true | |
admin: | |
pattern: ^/ | |
provider: users | |
guard: | |
authenticators: | |
- App\OAuthAuthenticator | |
logout: | |
path: auth.logout | |
target: auth.login | |
main: | |
anonymous: ~ | |
access_control: | |
- { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY } | |
- { path: ^/connect/google, role: IS_AUTHENTICATED_ANONYMOUSLY } | |
- { path: ^/.*, role: IS_AUTHENTICATED_FULLY } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App; | |
use App\User; | |
use Symfony\Component\Security\Core\User\UserInterface; | |
final class SecurityUser implements UserInterface | |
{ | |
/** | |
* @var string | |
*/ | |
private $email; | |
/** | |
* @var string[] | |
*/ | |
private $roles; | |
public function __construct(User $user) | |
{ | |
$this->email = $user->email(); | |
$this->roles = $user->roles();; | |
} | |
/** | |
* @return string[] | |
*/ | |
public function getRoles(): array | |
{ | |
return $this->roles; | |
} | |
public function getPassword(): string | |
{ | |
return ''; | |
} | |
public function getSalt(): string | |
{ | |
return ''; | |
} | |
public function getUsername(): string | |
{ | |
return $this->email->toString(); | |
} | |
public function eraseCredentials(): void | |
{ | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
services: | |
_defaults: | |
autowire: true | |
public: false | |
autoconfigure: true | |
League\OAuth2\Client\Provider\Google: | |
arguments: | |
$options: | |
clientId: '%env(APP_OAUTH_GOOGLE_CLIENT_ID)%' | |
clientSecret: '%env(APP_OAUTH_GOOGLE_CLIENT_SECRET)%' | |
redirectUri: '%env(APP_OAUTH_GOOGLE_REDIRECT_URI)%' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace App; | |
use Symfony\Component\Security\Core\User\UserInterface; | |
use Symfony\Component\Security\Core\User\UserProviderInterface; | |
final class UserProvider implements UserProviderInterface | |
{ | |
/** | |
* @var UserRepository | |
*/ | |
private $userRepository; | |
public function __construct(UserRepository $userRepository) | |
{ | |
$this->userRepository = $userRepository; | |
} | |
/** | |
* @param string $email | |
*/ | |
public function loadUserByUsername($email): SecurityUser | |
{ | |
return new SecurityUser($this->userRepository->getOneByEmail(new Email($email))); | |
} | |
public function refreshUser(UserInterface $user): SecurityUser | |
{ | |
return $this->loadUserByUsername($user->getUsername()); | |
} | |
public function supportsClass($class): bool | |
{ | |
return $class === SecurityUser::class; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment