Skip to content

OAuth🔗

Oauth login and register with hwi/oauth-bundle.

Installation🔗

1
composer require hwi/oauth-bundle

Configuration🔗

Import bundle routing:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# config/routes/hwi_oauth_routing.yaml
hwi_oauth_redirect:
    resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml"
    prefix:   /connect

hwi_oauth_connect:
    resource: "@HWIOAuthBundle/Resources/config/routing/connect.xml"
    prefix:   /connect

hwi_oauth_login:
    resource: "@HWIOAuthBundle/Resources/config/routing/login.xml"
    prefix:   /login

Configure the oauth providers you want:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# config/package/hwi_oauth.yaml
hwi_oauth:
    firewall_names: [your_firewall_name]

    resource_owners:
        facebook:
            type:           facebook
            client_id:      '%env(APP_FACEBOOK_ID)%'
            client_secret:  '%env(APP_FACEBOOK_SECRET)%'
            scope:          "email"

        google:
            type:           google
            client_id:      '%env(APP_GOOGLE_ID)%'
            client_secret:  '%env(APP_GOOGLE_SECRET)%'
            scope:          "email profile"

        linkedin:
            type:           linkedin
            client_id:      '%env(APP_LINKEDIN_ID)%'
            client_secret:  '%env(APP_LINKEDIN_SECRET)%'
            scope:          "r_emailaddress r_liteprofile"

Follow this guide to get your ID and Secret for your oauth providers.

Set all secrets and ids in .env.local (not commited) and in the vault.

Configure the firewall:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# config/packages/security.yaml
security:
    firewalls:
        your_firewall_name:
            # ...
            oauth:
                resource_owners:
                    facebook: "/fr/login/check-facebook"
                    linkedin: "/fr/login/check-linkedin"
                    google: "/fr/login/check-google"
                login_path: your_login_route_name
                check_path: your_login_check_route_name
                use_forward: false
                failure_path: your_failure_route_name # could be login route
                oauth_user_provider:
                    service: App\Infras\Security\Provider\OauthUserProvider

Model🔗

As a user could use several oauth accounts, we store each user oauth ids in a dedicated table with a many-to-one relation to user.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class OAuthId
{
    private User $user;
    private string $owner;
    private string $id;

    public function __construct(User $user, string $owner, string $id)
    {
        $this->user = $user;
        $this->owner = $owner;
        $this->id = $id;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping https://www.doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
  <entity name="App\Domain\Model\OAuthId" table="user_oauth_id">
    <id name="owner" type="string" column="owner"/>
    <id name="id" type="string" column="id"/>
    <id name="user" association-key="true"/>
    <many-to-one field="user" target-entity="App\Domain\Model\User" inversed-by="oauthIds" fetch="LAZY">
      <join-columns>
        <join-column name="user_id" referenced-column-name="id" on-delete="CASCADE" nullable=""/>
      </join-columns>
    </many-to-one>
  </entity>
</doctrine-mapping>

User provider🔗

We use the oauth login for both authentication and register processes. If the user exists in our database, we authenticate them. If the user does not exist, we create them.

 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
namespace App\Infras\Security\Provider;

use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthAwareUserProviderInterface;

class OauthUserProvider implements OAuthAwareUserProviderInterface
{
    public function loadUserByOAuthUserResponse(UserResponseInterface $response)
    {
        $owner = $response->getResourceOwner()->getName(); // oauth provider name
        $id = $response->getUsername(); // Unique idenfier in the oauth provider database
        $email = $response->getEmail(); // User email address

        $user = $this->userRepository->findOneByOauthId($owner, $id);

        if (null === $user) {
            $user = $this->userRepository->findOneByEmail($response->getEmail());
        }

        if (null === $user) {
            // Create user (register)
        } else {
            // Update user if you want (login)
        }

        return new SymfonyUser($user);
    }
}

Buttons🔗

Use these links to start oauth authentication process.

1
2
3
<a href="{{ path('hwi_oauth_service_redirect', { service: 'google' }) }}">Authenticate with Google</a>
<a href="{{ path('hwi_oauth_service_redirect', { service: 'facebook' }) }}">Authenticate with Facebook</a>
<a href="{{ path('hwi_oauth_service_redirect', { service: 'linkedin' }) }}">Authenticate with Linkedin</a>

You can use the same links for register.

1
2
3
<a href="{{ path('hwi_oauth_service_redirect', { service: 'google' }) }}">Register with Google</a>
<a href="{{ path('hwi_oauth_service_redirect', { service: 'facebook' }) }}">Register with Facebook</a>
<a href="{{ path('hwi_oauth_service_redirect', { service: 'linkedin' }) }}">Register with Linkedin</a>

Project references🔗


Last update: December 20, 2024