Search code examples
phplaravelmicrosoft-graph-apihttpresponseguzzle

MS Graph | PHP | GET Photo - Laravel 404 exception


I'm building a website with Azure authentication using MS Graph. As you can see below I want to login and get my own data as well as my managers which is working fine, however the issue begins when I want to select the photo.

$graph = new Graph();
$graph->setAccessToken($accessToken->getToken());
      
$user = $graph->createRequest('GET', '/me?$expand=manager($levels=1;$select=displayName,givenName,surname,mail)&$select=displayName,givenName,surname,mail&$count=true')    
   ->addHeaders(array("Content-Type" => "application/json"))
   ->setReturnType(Model\User::class)
   ->execute();
    
$photo = $graph->createRequest('GET', '/me/photo/$value')
   ->addHeaders(array("Content-Type" => "image/jpeg"))
   ->execute();
          
$photo = $photo->getRawBody();
$avatar = 'data:image/jpeg;base64,'.base64_encode($photo).'';

When a user does not have a profile photo set it will return a 404 Not Found which is ok, but I don't want my script to stop if there is no photo. What I want is something like this:

if($photo->getStatus(404)){
     $avatar = null;
}
else{
     $photo = $photo->getRawBody();
     $avatar = 'data:image/jpeg;base64,'.base64_encode($photo).'';
}     

If there is no photo I want to set $avatar to null instead of getting the following error: Laravel error description

Thanks in advance!

FULL 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());
      
        $user = $graph->createRequest('GET', '/me?$expand=manager($levels=1;$select=displayName,givenName,surname,mail)&$select=displayName,givenName,surname,mail&$count=true')    
          ->addHeaders(array("Content-Type" => "application/json"))
          ->setReturnType(Model\User::class)
          ->execute();
    
        $photo = $graph->createRequest('GET', '/me/photo/$value')
          ->addHeaders(array("Content-Type" => "image/jpeg"))
          ->execute();
          $photo = $photo->getRawBody();
          $avatar = 'data:image/jpeg;base64,'.base64_encode($photo).'';

        $manager = $user->getManager();

        $tokenCache = new TokenCache();
        $tokenCache->storeTokens($accessToken, $user, $manager, $avatar);     
        
        // Define user details and manager details
        $userFirstName = $user->getGivenName();
        $userSurname = $user->getSurname();
        $userEmail = $user->getMail();
  
        $managerFirstName = $manager->getGivenName();
        $managerSurname = $manager->getSurname();
        $managerEmail = $manager->getMail();

        return redirect('/');
      }
      catch (Exception $e) {
        $avatar = null;
        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'));
  }

Solution

  • Try to catch the exact exception the error is client exception of 404 status code try to catch it directly and catch its response. Also I have never heard of function $e->getResponseBody() it should be $e->getResponse() as given in guzzle docs. You can take more reference from this answer

    public function callback(Request $request)
      {
        // Validate state
        // ...
    
        
        // Initialize the OAuth client
          try {
            // Make the token request
            // ...
            // Define user details and manager details
            // ...
            
          }
          catch(\GuzzleHttp\Exception\ClientException $e){
                if($e->hasResponse()){
                   if ($e->getResponse()->getStatusCode() == '404'){
                        $avatar = null;
                        return redirect('/')
                          ->with('error', 'Error requesting access token')
                          ->with('errorDetail', json_encode($e->getResponse()));
                   }
                }
          }
          catch (Exception $e) {
            $avatar = null;
            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'));
      }