Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Microsoft Graph Laravel Package

microsoft/microsoft-graph

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation Add the package via Composer:

    composer require microsoft/microsoft-graph
    

    Requires PHP 8.2+.

  2. Register an Azure AD App

    • Go to Azure PortalAzure Active DirectoryApp registrationsNew registration.
    • Configure Redirect URI (for authorization_code flow) and API permissions (e.g., User.Read, Mail.ReadWrite).
    • Note tenantId, clientId, and clientSecret (or certificate).
  3. First Request (Client Credentials Flow)

    use Microsoft\Graph\GraphServiceClient;
    use Microsoft\Kiota\Authentication\Oauth\ClientCredentialContext;
    
    $tokenContext = new ClientCredentialContext('tenantId', 'clientId', 'clientSecret');
    $client = new GraphServiceClient($tokenContext);
    
    // Fetch a user (application permissions)
    $user = $client->users('user@domain.com')->get()->wait();
    echo $user->getDisplayName();
    
  4. First Request (User Delegation) Redirect users to Microsoft’s OAuth endpoint (e.g., /authorize?...), then exchange the authCode for a token:

    $tokenContext = new AuthorizationCodeContext('tenantId', 'clientId', 'clientSecret', $authCode, 'redirectUri');
    $client = new GraphServiceClient($tokenContext, ['User.Read']);
    $user = $client->me()->get()->wait();
    

Where to Look First


Implementation Patterns

Core Workflows

1. Authentication Flows

  • Client Credentials (App-Only) Use for background tasks (e.g., syncing data without user context).
    $client = new GraphServiceClient(
        new ClientCredentialContext('tenantId', 'clientId', 'clientSecret')
    );
    
  • Authorization Code (User Delegation) Use for web apps requiring user consent. Handle OAuth redirect manually:
    // After redirect from Microsoft's OAuth endpoint:
    $tokenContext = new AuthorizationCodeContext(
        'tenantId', 'clientId', 'clientSecret', $_GET['code'], 'https://your-app.com/callback'
    );
    $client = new GraphServiceClient($tokenContext, ['User.Read']);
    
  • On-Behalf-Of (Backend API Calls) Use when a frontend app passes a user token to your backend:
    $tokenContext = new OnBehalfOfContext('tenantId', 'clientId', 'clientSecret', $frontendToken);
    $client = new GraphServiceClient($tokenContext, ['Mail.Read']);
    

2. CRUD Operations

  • Async/Promise-Based API All requests return Promise objects. Use .wait() to block or handle callbacks:
    $user = $client->users()->post([
        'displayName' => 'John Doe',
        'mail' => 'john@example.com',
        'accountEnabled' => true
    ])->wait();
    
  • Paging Use .get() with top/skip or iterate over nextLink:
    $users = $client->users()->get()->wait();
    while ($users->getODataNextLink()) {
        $users = $client->users()->getNextPage($users->getODataNextLink())->wait();
    }
    

3. Batch Requests

Combine multiple requests into a single call:

$requests = [
    new GraphRequest('/users', 'GET'),
    new GraphRequest('/me/messages', 'GET', ['$top' => 10]),
];
$responses = $client->users()->sendBatchRequest($requests)->wait();

4. Error Handling

Wrap calls in try-catch for ApiException:

try {
    $user = $client->users('nonexistent@domain.com')->get()->wait();
} catch (ApiException $e) {
    $error = $e->getError();
    log("Error: {$error->getMessage()}, Code: {$error->getCode()}");
}

5. Custom HTTP Clients

Override Guzzle defaults (e.g., for proxies or timeouts):

use Microsoft\Graph\Core\GraphClientFactory;

$httpClient = GraphClientFactory::createWithConfig([
    'timeout' => 30,
    'proxy' => 'http://proxy.example.com',
]);
$client = GraphServiceClient::createWithRequestAdapter(
    new GraphRequestAdapter(
        new GraphPhpLeagueAuthenticationProvider($tokenContext),
        $httpClient
    )
);

6. National Clouds

Target China/US Gov clouds:

$client = new GraphServiceClient($tokenContext, [], NationalCloud::CHINA);

Gotchas and Tips

Pitfalls

  1. Token Expiry and Refresh

    • The SDK caches tokens in-memory by default. For long-running processes (e.g., CLI), tokens may expire before refresh. Use a persistent cache (e.g., Redis) or manually refresh:
      $tokenProvider = new GraphPhpLeagueAccessTokenProvider($tokenContext);
      $token = $tokenProvider->getAccessToken()->wait();
      
    • Gotcha: ClientCredentialContext tokens are cached by {tenantId}-{clientId}. Reuse the same $tokenContext instance for consistent caching.
  2. Async vs. Sync Confusion

    • Forgetting .wait() leads to silent failures. Use ->wait() or then() for synchronous/asynchronous handling:
      // Async with callback
      $client->me()->get()->then(
          fn($user) => echo $user->getDisplayName(),
          fn($ex) => error_log($ex->getMessage())
      );
      
  3. Scope Mismatches

    • Requests fail if scopes aren’t granted in Azure AD. Validate scopes before calling:
      $client = new GraphServiceClient($tokenContext, ['User.ReadWrite']); // Must match Azure AD permissions!
      
  4. Redirect URI Mismatch

    • For authorization_code flow, the redirectUri in the context must match the registered URI in Azure AD (case-sensitive).
  5. Rate Limiting

    • Microsoft Graph enforces throttling. Implement exponential backoff for retries:
      use Microsoft\Kiota\Abstractions\ApiException;
      use GuzzleHttp\Exception\RequestException;
      
      try {
          $response = $client->me()->get()->wait();
      } catch (ApiException $e) {
          if ($e->getStatusCode() === 429) {
              sleep($e->getRetryAfter());
              retry();
          }
      }
      
  6. Model Serialization

    • Complex objects (e.g., User) require proper serialization. Use ->toJson() or ->getProperty():
      $user = $client->me()->get()->wait();
      $email = $user->getMail(); // Direct property access
      

Debugging Tips

  1. Enable HTTP Logging Configure Guzzle to log requests/responses:

    $httpClient = GraphClientFactory::createWithConfig([
        'handler' => HandlerStack::create([
            new \GuzzleHttp\Middleware::tap(
                fn($request, $options) => error_log($request->getUri())
            ),
        ]),
    ]);
    
  2. Inspect Tokens Dump the cached token for debugging:

    $tokenProvider = new GraphPhpLeagueAccessTokenProvider($tokenContext);
    $token = $tokenProvider->getAccessToken()->wait();
    error_log($token->getToken());
    
  3. Validate Azure AD Permissions

Extension Points

  1. Custom Access Token Cache Implement AccessTokenCache for persistent storage (e.g., Redis):
    use Microsoft\Kiota\Authentication\Cache\AccessTokenCache;
    
    class RedisTokenCache implements AccessTokenCache {
        public function get($key): ?AccessToken { /* ... */ }
        public function set($key, AccessToken $token): void { /* ... */ }
    }
    
    $client = GraphServiceClient::createWithAuthenticationProvider(
        GraphPhpLeagueAuthenticationProvider::createWithAccessTokenProvider
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle
dmstr/api-platform-utils-bundle
dmstr/api-configuration-bundle
chrisdev/ux-components
baks-dev/finances
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle