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. Install the SDK:

    composer require microsoft/microsoft-graph
    

    Ensure PHP 8.2+ is used.

  2. Register an Azure AD App:

    • Go to Azure PortalAzure Active DirectoryApp registrationsNew registration.
    • Configure Redirect URI (for auth code flow) and API permissions (e.g., User.Read, Mail.ReadWrite).
    • Note tenantId, clientId, and clientSecret (or certificate).
  3. First Use Case: Fetch a User

    use Microsoft\Graph\GraphServiceClient;
    use Microsoft\Kiota\Authentication\Oauth\ClientCredentialContext;
    
    $tokenRequestContext = new ClientCredentialContext(
        'your-tenant-id',
        'your-client-id',
        'your-client-secret'
    );
    
    $client = new GraphServiceClient($tokenRequestContext);
    $user = $client->users()->byUserId('user@domain.com')->get()->wait();
    echo $user->getDisplayName();
    

Implementation Patterns

Authentication Workflows

  1. Client Credentials (App-Only Auth):

    • Use ClientCredentialContext for background services (e.g., cron jobs, APIs).
    • Example: Syncing SharePoint data without user interaction.
    $client = new GraphServiceClient(
        new ClientCredentialContext('tenantId', 'clientId', 'clientSecret')
    );
    
  2. Authorization Code (User Delegation):

    • Use AuthorizationCodeContext for web apps requiring user consent.
    • Redirect users to Microsoft’s OAuth endpoint, then exchange the authCode for a token.
    $tokenRequestContext = new AuthorizationCodeContext(
        'tenantId', 'clientId', 'clientSecret', $authCode, 'https://your-app.com/callback'
    );
    
  3. On-Behalf-Of (Backend API Calls):

    • Use OnBehalfOfContext when a frontend app passes a user token to a backend.
    • Example: A React frontend calls a Laravel API, which then queries Graph.
    $tokenRequestContext = new OnBehalfOfContext(
        'tenantId', 'clientId', 'clientSecret', $frontendAccessToken
    );
    

Common CRUD Operations

  1. Fetch Data (Async/Promise-Based):

    $user = $client->me()->get()->wait(); // User.Read scope required
    $emails = $client->users('user@domain.com')->messages()->get()->wait();
    
  2. Create/Update Data:

    $newUser = new \Microsoft\Graph\Model\User();
    $newUser->setDisplayName('John Doe');
    $createdUser = $client->users()->post($newUser)->wait();
    
  3. Batch Requests:

    $batch = $client->createBatch();
    $batch->users('user@domain.com')->messages()->get();
    $batch->users('user@domain.com')->calendar()->events()->get();
    $results = $batch->execute()->wait();
    

Integration with Laravel

  1. Service Provider Setup: Bind the client to Laravel’s container in AppServiceProvider:

    public function register()
    {
        $this->app->singleton(GraphServiceClient::class, function ($app) {
            $tokenRequestContext = new ClientCredentialContext(
                config('services.graph.tenant_id'),
                config('services.graph.client_id'),
                config('services.graph.client_secret')
            );
            return new GraphServiceClient($tokenRequestContext);
        });
    }
    
  2. Middleware for Token Refresh: Use Laravel middleware to handle token refreshes transparently:

    public function handle($request, Closure $next)
    {
        $client = app(GraphServiceClient::class);
        // Check token expiry and refresh if needed
        return $next($request);
    }
    
  3. Jobs for Async Operations: Offload long-running Graph operations to Laravel queues:

    use Microsoft\Graph\GraphServiceClient;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    
    class SyncGraphData implements ShouldQueue
    {
        use Queueable;
    
        public function handle(GraphServiceClient $client)
        {
            $client->users()->get()->wait();
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Token Expiry Handling:

    • The SDK caches tokens in-memory by default. For long-running processes (e.g., CLI commands), tokens may expire. Use a persistent cache (e.g., Redis) or manually refresh tokens.
    • Example with Redis cache:
      use Microsoft\Kiota\Authentication\Cache\RedisAccessTokenCache;
      use Predis\Client as RedisClient;
      
      $redis = new RedisClient(['scheme' => 'tcp', 'host' => 'localhost']);
      $cache = new RedisAccessTokenCache($redis);
      $client = GraphServiceClient::createWithAuthenticationProvider(
          GraphPhpLeagueAuthenticationProvider::createWithAccessTokenProvider(
              GraphPhpLeagueAccessTokenProvider::createWithCache($cache)
          )
      );
      
  2. Async Operations:

    • Forgetting to call .wait() on promises will leave requests unresolved. Always chain .wait() for synchronous behavior.
    • Example of anti-pattern:
      // ❌ Missing .wait() – request fires but result is ignored
      $client->me()->get();
      
  3. Scope Mismatches:

    • Ensure scopes match the permissions configured in Azure AD. Missing scopes cause 403 Forbidden errors.
    • Example: User.Read is required for $client->me()->get().
  4. National Clouds:

    • Defaults to graph.microsoft.com. For China/Germany clouds, specify:
      $client = new GraphServiceClient($tokenRequestContext, [], NationalCloud::CHINA);
      

Debugging

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

    $guzzleConfig = [
        'debug' => fopen('graph_debug.log', 'w'),
        'curl' => function ($curl) {
            $curl->setopt(CURLOPT_VERBOSE, true);
        }
    ];
    $httpClient = GraphClientFactory::createWithConfig($guzzleConfig);
    
  2. Handle API Exceptions: Catch Microsoft\Kiota\Abstractions\ApiException for Graph-specific errors:

    try {
        $user = $client->users()->byUserId('user@domain.com')->get()->wait();
    } catch (ApiException $e) {
        if ($e->getStatusCode() === 401) {
            // Token expired or invalid
        }
        throw $e;
    }
    

Tips

  1. Use Strong Typing: Leverage PHP’s return types for Graph models:

    /** @var \Microsoft\Graph\Model\User $user */
    $user = $client->me()->get()->wait();
    
  2. Pagination: Handle paginated responses with $nextLink:

    $users = $client->users()->get()->wait();
    while ($users->getODataNextLink()) {
        $users = $client->getRequestAdapter()
            ->getRequestInformation($users->getODataNextLink())
            ->wait();
    }
    
  3. Rate Limiting: Microsoft Graph enforces throttling policies. Implement exponential backoff for retries:

    use Symfony\Component\HttpClient\RetryableHttpClient;
    use Symfony\Component\HttpClient\Retry\RetryStrategy;
    
    $retryStrategy = new RetryStrategy(3, 1000); // 3 retries, 1s delay
    $httpClient = new RetryableHttpClient($guzzleClient, $retryStrategy);
    
  4. Environment-Specific Config: Store credentials in Laravel’s .env:

    GRAPH_TENANT_ID=your-tenant-id
    GRAPH_CLIENT_ID=your-client-id
    GRAPH_CLIENT_SECRET=your-client-secret
    

    Then inject into ClientCredentialContext:

    $tokenRequestContext = new ClientCredentialContext(
        config('services.graph.tenant_id'),
        config('services.graph.client_id'),
        config('services.graph.client_secret')
    );
    
  5. Testing: Use the Graph Explorer to test endpoints before implementing. Mock the SDK in PHPUnit:

    $mockClient = $this->createMock(GraphServiceClient::class);
    $mockClient->method('users')->willReturnSelf();
    $mockClient->method('byUserId')->willReturnSelf();
    $mockClient->method('get')->willReturn(new Promise(function ($resolve) {
        $resolve(new \Microsoft\Graph\Model\User());
    }));
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky