- Documentation >
- Guide >
- Users >
- User authentication >
- Add login through external service
Add login through external service
To add an option to log in to the system through an external service, you can use OAuth2 to authorize your users.
The example below shows how to add a Log in with Google option to the Back Office.
Configure the OAuth2 client in config/packages/knpu_oauth2_client.yaml
:
| knpu_oauth2_client:
clients:
# Configure your clients as described here: https://github.com/knpuniversity/oauth2-client-bundle#configuration
google:
type: google
client_id: '%env(OAUTH_GOOGLE_CLIENT_ID)%'
client_secret: '%env(OAUTH_GOOGLE_CLIENT_SECRET)%'
# Redirect route:
redirect_route: ibexa.oauth2.check
redirect_params:
identifier: google
|
Enable OAuth authentication
Enable OAuth2 authentication through Google for the site
SiteAccess:
| ezplatform:
system:
admin:
oauth2:
enabled: true
clients: ['google']
|
Add the Ibexa\Platform\OAuth2Client\Security\Authenticator\OAuth2Authenticator
guard authenticator
to your firewall configuration in config/packages/security.yaml
and ensure that the ibexa.oauth2.connect
route is accessible by an anonymous user:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 | oauth2_connect:
pattern: /oauth2/connect/*
security: false
ezpublish_front:
pattern: ^/
user_checker: eZ\Publish\Core\MVC\Symfony\Security\UserChecker
anonymous: ~
ezpublish_rest_session: ~
guard:
authenticators:
- 'Ibexa\Platform\Bundle\OAuth2Client\Security\Authenticator\OAuth2Authenticator'
form_login:
require_previous_session: false
csrf_token_generator: security.csrf.token_manager
logout: ~
|
Implement a resource owner mapper
Create a resource owner mapper for Google login in src/OAuth/GoogleResourceOwnerMapper.php
.
The mapper extends ResourceOwnerToExistingOrNewUserMapper
,
which enables it to create a new user in the Repository if the user does not exist yet.
The mapper loads a user (line 50) or creates a new one (line 60),
based on the information from resourceOwner
, that is the OAuth provider.
The new user name is set with a google:
prefix (lines 18, 105), to avoid conflicts with users registered in a regular way.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 | <?php
declare(strict_types=1);
namespace App\OAuth;
use eZ\Publish\API\Repository\LanguageResolver;
use eZ\Publish\API\Repository\Repository;
use eZ\Publish\API\Repository\Values\ContentType\ContentType;
use Ibexa\Platform\OAuth2Client\Repository\OAuth2UserService;
use Ibexa\Platform\OAuth2Client\ResourceOwner\ResourceOwnerToExistingOrNewUserMapper;
use League\OAuth2\Client\Provider\GoogleUser;
use League\OAuth2\Client\Provider\ResourceOwnerInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
final class GoogleResourceOwnerMapper extends ResourceOwnerToExistingOrNewUserMapper
{
private const PROVIDER_PREFIX = 'google:';
/** @var \Ibexa\Platform\OAuth2Client\Repository\OAuth2UserService */
private $userService;
/** @var \eZ\Publish\API\Repository\LanguageResolver */
private $languageResolver;
/** @var string|null */
private $contentTypeIdentifier;
/** @var string|null */
private $parentGroupRemoteId;
public function __construct(
Repository $repository,
OAuth2UserService $userService,
LanguageResolver $languageResolver,
?string $contentTypeIdentifier = null,
?string $parentGroupRemoteId = null
) {
parent::__construct($repository);
$this->userService = $userService;
$this->languageResolver = $languageResolver;
$this->contentTypeIdentifier = $contentTypeIdentifier;
$this->parentGroupRemoteId = $parentGroupRemoteId;
}
/**
* @param \League\OAuth2\Client\Provider\GoogleUser $resourceOwner
*/
protected function loadUser(
ResourceOwnerInterface $resourceOwner,
UserProviderInterface $userProvider
): ?UserInterface {
return $userProvider->loadUserByUsername($this->getUsername($resourceOwner));
}
/**
* @param \League\OAuth2\Client\Provider\GoogleUser $resourceOwner
*/
protected function createUser(
ResourceOwnerInterface $resourceOwner,
UserProviderInterface $userProvider
): ?UserInterface {
$userCreateStruct = $this->userService->newOAuth2UserCreateStruct(
$this->getUsername($resourceOwner),
$resourceOwner->getEmail(),
$this->getMainLanguageCode(),
$this->getOAuth2UserContentType($this->repository)
);
$userCreateStruct->setField('first_name', $resourceOwner->getFirstName());
$userCreateStruct->setField('last_name', $resourceOwner->getLastName());
$parentGroups = [];
if ($this->parentGroupRemoteId !== null) {
$parentGroups[] = $this->userService->loadUserGroupByRemoteId($this->parentGroupRemoteId);
}
$this->userService->createUser($userCreateStruct, $parentGroups);
return $userProvider->loadUserByUsername($this->getUsername($resourceOwner));
}
private function getOAuth2UserContentType(Repository $repository): ?ContentType
{
if ($this->contentTypeIdentifier !== null) {
$contentTypeService = $repository->getContentTypeService();
return $contentTypeService->loadContentTypeByIdentifier(
$this->contentTypeIdentifier
);
}
return null;
}
private function getMainLanguageCode(): string
{
// Get first prioritized language for current scope
return $this->languageResolver->getPrioritizedLanguages()[0];
}
private function getUsername(GoogleUser $resourceOwner): string
{
return self::PROVIDER_PREFIX . $resourceOwner->getId();
}
}
|
Configure the service by using the ibexa.oauth2_client.resource_owner_mapper
tag:
| App\OAuth\GoogleResourceOwnerMapper:
tags:
- { name: ibexa.oauth2_client.resource_owner_mapper, identifier: google }
|
Add template
To add a Log in with Google button to your Back Office login form, create the following template file
in templates/themes/admin/account/login/oauth2_login.html.twig
:
| <div class="row mt-4">
<div class="col">
<p class="text-center">or</p>
<div class="btn-group d-flex">
<a href="{{ ibexa_oauth2_connect_path('google') }}" class="btn btn-primary">
Log in via Google
</a>
</div>
</div>
</div>
|
Finally, add the template to the login form by using the login-form-after
component:
| app.components.oauth2_login:
parent: EzSystems\EzPlatformAdminUi\Component\TwigComponent
arguments:
$template: '@@ezdesign/account/login/oauth2_login.html.twig'
tags:
- { name: ezplatform.admin_ui.component, group: login-form-after }
|