API permissions : Unable to retrieve Microsoft Ads account and Merchant Center data using Microsoft Azure Active Directory
Tags: api, microsoft, microsoftads, laravel
Published: 2024-04-26 11:41:45

0

I'm working on a Laravel project using Socialite to authenticate and log in users with their Microsoft accounts. I've created an application in the Azure portal with the "Supported account types: All Microsoft account users" setting. The authentication process is working fine, and I can successfully fetch basic user details such as ID, name, and email. However, I'm unable to retrieve the user's Ads account and Merchant Center information using Microsoft Azure Active Directory. I've checked the Azure portal, but I cannot find the necessary API permissions/scopes, such as `ads.manage`. I would like to know how to enable these permissions and properly configure my Azure application to fetch the required data.

`<?php

namespace SocialiteProviders\Microsoft;

use Illuminate\Support\Arr;
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Facades\Log;
use GuzzleHttp\Exception\ClientException;
use SocialiteProviders\Manager\OAuth2\AbstractProvider;
use SocialiteProviders\Microsoft\MicrosoftUser as User;

class Provider extends AbstractProvider
{
    public const IDENTIFIER = 'MICROSOFT';

    protected const DEFAULT_FIELDS_USER = ['id', 'displayName', 'userPrincipalName'];
    protected const DEFAULT_FIELDS_ADS_ACCOUNTS = ['id', 'name', 'customerId'];
    protected const DEFAULT_FIELDS_MERCHANT_ACCOUNTS = ['id', 'name'];

    protected $scopes = [
        'https://graph.microsoft.com/User.Read',
        'https://ads.microsoft.com/msads.manage',
        'offline_access',
    ];

    protected function getAuthUrl($state)
    {
        return $this->buildAuthUrlFromBase(
            'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
            $state
        );
    }

    protected function getTokenUrl()
    {
        return 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
    }

    protected function getUserByToken($token)
    {
        $user = $this->getUserData($token, 'https://graph.microsoft.com/v1.0/me', self::DEFAULT_FIELDS_USER);

        if (!$user) {
            return [];
        }

        try {
            $adsAccounts = $this->getUserData($token, 'https://ads.microsoft.com/api/v13/accounts', self::DEFAULT_FIELDS_ADS_ACCOUNTS);
        } catch (ClientException $e) {
            Log::error('Failed to fetch ads accounts', ['exception' => $e, 'user' => $user]);
            $adsAccounts = [];
        }

        try {
            $merchantAccounts = $this->getUserData($token, 'https://marketing.microsoft.com/rest/v1/merchantcenters', self::DEFAULT_FIELDS_MERCHANT_ACCOUNTS);
        } catch (ClientException $e) {
            Log::error('Failed to fetch merchant accounts', ['exception' => $e, 'user' => $user]);
            $merchantAccounts = [];
        }

        $user['adsAccounts'] = $adsAccounts;
        $user['merchantAccounts'] = $merchantAccounts;

        return $user;
    }

    protected function mapUserToObject(array $user)
    {
        return (new User())->setRaw($user)->map([
            'id' => $user['id'],
            'nickname' => null,
            'name' => $user['displayName'],
            'email' => $user['userPrincipalName'],
            'avatar' => Arr::get($user, 'avatar'),
            'adsAccounts' => Arr::get($user, 'adsAccounts'),
            'merchantAccounts' => Arr::get($user, 'merchantAccounts'),
            'tenant' => Arr::get($user, 'tenant'),
        ]);
    }

    protected function getTokenFields($code)
    {
        return array_merge(parent::getTokenFields($code), [
            'scope' => $this->formatScopes($this->getScopes(), $this->scopeSeparator),
        ]);
    }

    public static function additionalConfigKeys()
    {
        return ['tenant', 'include_tenant_info', 'include_avatar', 'include_avatar_size', 'fields', 'tenant_fields'];
    }

    protected function getUserData($token, $url, $fields)
    {
        $response = $this->getHttpClient()->get($url, [
            RequestOptions::HEADERS => [
                'Accept' => 'application/json',
                'Authorization' => 'Bearer ' . $token,
            ],
            RequestOptions::QUERY => [
                '$select' => implode(',', $fields),
            ],
        ]);

        $data = json_decode((string) $response->getBody(), true);

        if (!$data) {
            return [];
        }

        return $data;
    }
}

    'microsoft' => [
    'client_id' => env('MICROSOFT_CLIENT_ID'),
    'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
    'tenant_id' => env('MICROSOFT_TENANT_ID'),
    'redirect' => env('MICROSOFT_REDIRECT_URI'),
    'tenant' => 'common',
    'include_tenant_info' => true,
],



MICROSOFT_CLIENT_ID=*****
MICROSOFT_CLIENT_SECRET=***
MICROSOFT_TENANT_ID=**
MICROSOFT_REDIRECT_URI=https://infinitemsfeed.com/microsoft/auth




    public function redirectToMicrosoft()
    {
        return Socialite::driver('microsoft')->redirect();
    }
    
    public function handleMicrosoftCallback()
    {
        // return "abcdefghi";
        $user = Socialite::driver('microsoft')->user();
    
        return $user;
    }

const handleMicrosoftLogin = () => {
  window.open("https://infinitemsfeed.com/auth/microsoft?token=" + window.sessionToken, "_blank")
}`


![Image of azure portal permission dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9sw08ot587wyd4oom14y.png)

**I'm facing issues with setting up API permissions or scopes**