1

I need a little help understanding how often I should be requesting an Access Token when using the Microsoft Graph API. I already have the Enterprise Application created with the proper permissions - everything is working as it should be but I'm not certain I'm correctly using it...

We have a custom Company Directory that loads user profile pictures and their Microsoft Teams presence for each user. Currently I'm requesting the access token on each page load. But is this necessary? Is there a more efficient way to do this such as storing the Access Token in a session? How long does the token last? I'm having a bit of trouble comprehending all this. Any guidance would be greatly appreciated.

I'm requesting the Access Token on each page load by calling a function getAccessToken().

//Get Microsoft Graph API Access Token
function getAccessToken() {
    // Set up the request parameters
    $clientId = "";
    $clientSecret = "";
    $tenant_id = "";
    $grantType = "client_credentials";
    $resource = "https://graph.microsoft.com";
    $tokenEndpoint = "https://login.microsoftonline.com/$tenant_id/oauth2/token";

    // Build the request body
    $requestBody = "client_id=$clientId&client_secret=$clientSecret&grant_type=$grantType&resource=$resource";

    // Set up the curl options
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $tokenEndpoint);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

    // Execute the request
    $response = curl_exec($ch);
    curl_close($ch);

    // Extract the access token from the response
    $responseJson = json_decode($response, true);
    $accessToken = $responseJson["access_token"];
    return $accessToken;
}

Then depending on the page loaded, I call the getAccessToken() function once at the top of my script and then perform numerous Microsoft Graph API calls for things like profile pictures, user data, and presence information.

Is this the correct way of leveraging the Access Token?

5
  • How long does the token last...the response you get when you receive the access token should also include an expiry time. Have a look at the rest of the $responseJson object. See also learn.microsoft.com/en-us/graph/auth-v2-service#token-response Commented Jan 10, 2023 at 14:07
  • Normally then you can re-use that token as many times as you like until it expires, and request a new one by going right back through the auth process. It's all pretty standard OAuth behaviour, but also you should read the MS documentation on this kind of stuff (it's not specific to PHP). So yeah, you could store the token in the Session, or securely in a database, or whatever you like. Commented Jan 10, 2023 at 14:08
  • learn.microsoft.com/en-us/graph/auth, learn.microsoft.com/en-us/graph/auth-v2-service Commented Jan 10, 2023 at 14:10
  • better to get access token and store it and refresh it in case of 401 response than to retrieve it each request otherwise you may get error for multiple requests learn.microsoft.com/en-us/azure/active-directory/develop/… Commented Jan 10, 2023 at 15:38
  • 1
    The answer button was missing earlier which is why I improvised. Fixed now. Thank you. Commented Jan 30, 2023 at 23:20

1 Answer 1

1

I came up with the following functions after looking at some other examples. I know it's not perfect and won't handle every token circumstance, but it's been working for me so far. Feel free to rip me apart - I'm not a developer. I'm just dangerous enough to hack things together.

function getAccessToken() {
    //Generate a token if it doesn't already exist and store it in a session. 
    if (!isset($_SESSION['access_token']) || !isset($_SESSION['expires_on'])) {
        $accessToken = generateAccessToken();
        $_SESSION['access_token'] = $accessToken['access_token'];
        $_SESSION['expires_on'] = $accessToken['expires_on'];
        return $accessToken;
    } else {
        //check if token is expired or not
        $expires_on = $_SESSION['expires_on']; // Unix timestamp
        $current_time = time();
        //Check if token expiry has passed and regenerate token. Othwerwise, return the stored token from the session variables.
        if($current_time >= $expires_on){
            $accessToken = generateAccessToken();
            $_SESSION['access_token'] = $accessToken['access_token'];
            $_SESSION['expires_on'] = $accessToken['expires_on'];
            return $accessToken;
        } Else {
            return $_SESSION;
        }
    }
}

function generateAccessToken() {        
    // Set up the request parameters
    global $clientId, $clientSecret, $tenant_id;

    $grantType = "client_credentials";
    $resource = "https://graph.microsoft.com";
    $tokenEndpoint = "https://login.microsoftonline.com/$tenant_id/oauth2/token";

    // Build the request body
    $requestBody = "client_id=$clientId&client_secret=$clientSecret&grant_type=$grantType&resource=$resource";

    // Set up the curl options
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $tokenEndpoint);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $requestBody);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    // Execute the request
    $response = curl_exec($ch);
    curl_close($ch);

    // Extract the access token from the response
    $responseJson = json_decode($response, true);
    //$accessToken = $responseJson["access_token"];
    //return $accessToken;
    return $responseJson;
}

And then I'm using the token to query the Microsoft Graph API. Here's an example of grabbing a user's profile photo using getUserPhotoFromGraphAPI([email protected]):

function getUserPhotoFromGraphAPI ($mail) {
    // First, obtain an access token for the Microsoft Graph API
    global $noProfilePicture;
    
    //Get Access Token
    $accessToken = getAccessToken();

    // Next, use the Microsoft Graph API to get the user's profile picture
    $ch = curl_init();
    $url = 'https://graph.microsoft.com/v1.0/users/' . $mail . '/photo/$value';
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer " . $accessToken['access_token']));
    $output = curl_exec($ch);
    $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $err = curl_error($ch);
    curl_close($ch);

    // The profile picture is returned as a binary stream. 
    //print_r($output);
    //$json = json_decode($output);
    if ($err) { 
        //echo "cURL Error #:" . $err; 
        return null;
    } 
    else {      
        if($httpcode == 200) {          
            //The photo is returned in binary form, we need to convert it to Base64 for storage in MySQL
            $dataUri =  chunk_split(base64_encode($output));
            $imageBase64 = "data:image/jpeg;base64,$dataUri";
            
            //Return the file name
            return $imageBase64;
        } else {
            //Return the no profile picture found file name from config.php
            return $noProfilePicture;
        }
    }   
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.