Video Tutorial Social Authentication on Symfony


Welcome to this video where I invite you to discover how to set up authentication via social networks using the KnpUOAuth2ClientBundle bundle.

00:00 Introduction and configuration of the symfony application
08:40 Using KnpUOAuth2ClientBundle
36:08 Get the email in the case of github

The stages of implementation

First, you will have to install the bundle as well as the client you want to set up.

composer require knpuniversity / oauth2-client-bundle
composer require league / oauth2-github

Then we will create an OAuth application on the social network that interests us and recover the id and the secret key that we put in our environment variable.

GITHUB_ID = c39f620296adf6722a5c
GITHUB_SECRET = 37eaa24ec6d843e52fa80bbc2ba9055e475db8e4

We configure our client by modifying the file config / packages / knpu_oauth2_client.yaml

knpu_oauth2_client:
    clients:
        github:
            type: github
            client_id: '% env (GITHUB_ID)%'
            client_secret: '% env (GITHUB_SECRET)%'
            redirect_route: oauth_check
            redirect_params:
                service: github

This customer can then be retrieved through the service KnpU OAuth2ClientBundle Client ClientRegistry. It will also be used to redirect the user to the authentication portal.

/ **
 * @Route ("/ connect / github", name = "github_connect")
 * /
public function connect (ClientRegistry $ clientRegistry): RedirectResponse
{
    / ** @var GithubClient $ client * /
    $ client = $ clientRegistry-> getClient ('github');
    return $ client-> redirect (('read: user', 'user: email'));
}

To manage the return, we will use a route that will be intercepted by our authenticator.

# config / routes.yaml
oauth_check:
  path: / oauth / check / {service}
  controller: Symfony  Bundle  FrameworkBundle  Controller  TemplateController
``

Finally, all we have to do is create the authenticator which will intercept the request and authenticate the user.

`` php
router = $ router;
        $ this-> clientRegistry = $ clientRegistry;
        $ this-> userRepository = $ userRepository;
    }

    public function start (Request $ request, AuthenticationException $ authException = null)
    {
        return new RedirectResponse ($ this-> router-> generate ('app_login'));
    }

    / **
     * If the route corresponds to the expected one, then we trigger this authenticator
    ** /
    public function supports (Request $ request)
    {
        return 'oauth_check' === $ request-> attributes-> get ('_ route') && $ request-> get ('service') === 'github';
    }

    public function getCredentials (Request $ request)
    {
        return $ this-> fetchAccessToken ($ this-> getClient ());
    }

    / **
     * Retrieves the user from the AccessToken
     *
     * @param AccessToken $ credentials
     * /
    public function getUser ($ credentials, UserProviderInterface $ userProvider)
    {
        / ** @var GithubResourceOwner $ githubUser * /
        $ githubUser = $ this-> getClient () -> fetchUserFromToken ($ credentials);

        // We get the user's email (specific to github)
        $ response = HttpClient :: create () -> request (
            'GET',
            'https://api.github.com/user/emails',
            (
                'headers' => (
                    'authorization' => "token {$ credentials-> getToken ()}"
                )
            )
        );
        $ emails = json_decode ($ response-> getContent (), true);
        foreach ($ emails as $ email) {
            if ($ email ('primary') === true && $ email ('verified') === true) {
                $ data = $ githubUser-> toArray ();
                $ data ('email') = $ email ('email');
                $ githubUser = new GithubResourceOwner ($ data);
            }
        }

        if ($ githubUser-> getEmail () === null) {
            throw new NotVerifiedEmailException ();
        }

        return $ this-> userRepository-> findOrCreateFromGithubOauth ($ githubUser);
    }

    public function onAuthenticationFailure (Request $ request, AuthenticationException $ exception)
    {
        if ($ request-> hasSession ()) {
            $ request-> getSession () -> set (Security :: AUTHENTICATION_ERROR, $ exception);
        }

        return new RedirectResponse ($ this-> router-> generate ('app_login'));
    }

    public function onAuthenticationSuccess (Request $ request, TokenInterface $ token, string $ providerKey)
    {
        $ targetPath = $ this-> getTargetPath ($ request-> getSession (), $ providerKey);
        return new RedirectResponse ($ targetPath?: '/');
    }

    private function getClient (): GithubClient {
        return $ this-> clientRegistry-> getClient ('github');
    }
}

And There you go ! All you have to do is make the code more generic in order to adapt it to other social networks;)