BAKO Blog

Laravel Authentication with Azure Active Directory

2022-07-12

To implement authentication on Laravel through Azure Active Directory is pretty straightforward. Its a multi-step process and involves configuring an Application on Azure Portal. So lets start with configuration. In Azure portal click Manage Azure Active Directory and then App Registrations. Click New Registration and fill in App Name, select the scope of accounts that will be able to authenticate and setup Web Redirect URL. Redirect URL is your endpoint where all authentication logic with passed OAuth state will happen.

So first of all we have to have a login button on our front-end that directs user to Azure authentication URL. Which in turn redirects back to our callback endpoint and passes OAuth state to our backend. We need to assign a Laravel API endpoint to our AuthController function:

public function callback(Request $request)
{
    // Validate state
    $expectedState = session('oauthState');
    $request->session()->forget('oauthState');
    $providedState = $request->query('state');

    if (!isset($expectedState)) {
        // If there is no expected state in the session,
        // do nothing and redirect to the home page.
        return redirect('/');
    }

    if (!isset($providedState) || $expectedState != $providedState) {
    return redirect('/')
        ->with('error', 'Invalid auth state')
        ->with('errorDetail', 'The provided auth state did not match the expected value');
    }

    // Authorization code should be in the "code" query param
    $authCode = $request->query('code');
    if (isset($authCode)) {
        // Initialize the OAuth client
        $oauthClient = new \League\OAuth2\Client\Provider\GenericProvider([
            'clientId'                => config('azure.appId'),
            'clientSecret'            => config('azure.appSecret'),
            'redirectUri'             => config('azure.redirectUri'),
            'urlAuthorize'            => config('azure.authority').config('azure.authorizeEndpoint'),
            'urlAccessToken'          => config('azure.authority').config('azure.tokenEndpoint'),
            'urlResourceOwnerDetails' => '',
            'scopes'                  => config('azure.scopes')
        ]);

        try {
            // Make the token request
            $accessToken = $oauthClient->getAccessToken('authorization_code', [
                'code' => $authCode
            ]);

            $graph = new Graph();
            $graph->setAccessToken($accessToken->getToken());

            $graphuser = $graph->createRequest('GET', '/me?$select=displayName,mail,userPrincipalName,mobilePhone,department')
                ->setReturnType(\Microsoft\Graph\Model\User::class)
                ->execute();

            if ($graphuser->getProperties()['mail'] != '') {

                $person = Person::where('email', strtolower($graphuser->getProperties()['mail']))->first();
                // Create new user in database if it doesn't exist
                if (!$person) {
                    $person = new Person();
                    $person->email = strtolower($graphuser->getProperties()['mail']);
                    $person->fullName = $graphuser->getProperties()['displayName'];
                    $person->firstName = explode(' ', $graphuser->getProperties()['displayName'])[0];
                    $person->lastName = explode(' ', $graphuser->getProperties()['displayName'])[1];
                    $person->save();

                    $user = new User();
                    $user->personId = $person->id;
                    $user->save();
                }
                $user = User::where('personId', $person->id)->first();

                $user->apiToken = $this->genToken();
                $user->lastSeen = Carbon::now();
                if ($user->save()) {
                    return redirect('https://example.com/callback?token='.$user->apiToken);
                }
            }

            return redirect('/');
        }

        catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
            return redirect('/')
                ->with('error', 'Error requesting access token')
                ->with('errorDetail', json_encode($e->getResponseBody()));
        }
    }

    return redirect('/')
        ->with('error', $request->query('error'))
        ->with('errorDetail', $request->query('error_description'));
}
                    

Make sure to fill in Laravel config with required OAuth values. Now you only need to catch authorization token on your frontend where backend callback sends user after authentication. Feel free to inquire further details of this process, by contacting the email address at the bottom of this page.

Get in touch

blog@bako.co

BAKO