Msg.Client (msg v0.3.8)

Responsible for handling authentication and request setup for interacting with the Microsoft Graph API.

Supports three authentication strategies:

1. Client Credentials (Application-Only)

Use for application-level permissions (User.ReadWrite.All, Group.ReadWrite.All, etc.):

credentials = %{
  client_id: "app-id",
  client_secret: "secret",
  tenant_id: "tenant-id"
}

client = Msg.Client.new(credentials)
{:ok, users} = Msg.Users.list(client)

Best for: User management, group management, user calendars

2. Pre-existing Access Token

Use when token lifecycle is managed externally (e.g., by a GenServer):

access_token = TokenManager.get_token(org_id: 123)
client = Msg.Client.new(access_token)

Best for: Production apps with token management GenServer

3. Refresh Token (Delegated Permissions)

Use for delegated permissions (Calendars.ReadWrite.Shared, etc.):

client = Msg.Client.new(refresh_token, credentials)

Best for: One-off operations, testing, admin tools

See Msg.Auth for obtaining refresh tokens via OAuth authorization code flow.

Required Permissions

Different resources require different permission types:

ResourceApplication PermissionDelegated Permission
User calendarsCalendars.ReadWriteCalendars.ReadWrite
Group calendars❌ Not supportedCalendars.ReadWrite.Shared
User managementUser.ReadWrite.AllN/A
Group managementGroup.ReadWrite.AllN/A

References

Summary

Functions

Fetches an access token using client credentials flow.

Creates an authenticated HTTP client for Microsoft Graph API.

Types

credentials()

@type credentials() :: %{
  client_id: String.t(),
  client_secret: String.t(),
  tenant_id: String.t()
}

token_provider()

@type token_provider() :: (credentials() -> String.t())

Functions

fetch_token!(map)

@spec fetch_token!(credentials()) :: String.t()

Fetches an access token using client credentials flow.

This is used internally by new/1 when called with a credentials map. You typically don't need to call this directly.

Parameters

  • credentials - Map with :client_id, :client_secret, and :tenant_id

Returns

Access token string

Raises

Raises if token fetch fails (invalid credentials, network error, etc.)

new(credentials_or_token, token_provider_or_credentials \\ &fetch_token!/1)

@spec new(credentials() | String.t(), token_provider() | credentials()) ::
  Req.Request.t() | {:error, term()}

Creates an authenticated HTTP client for Microsoft Graph API.

Supports multiple authentication patterns via overloaded function signatures.

1-arity: Client Credentials or Access Token

With credentials map:

credentials = %{
  client_id: "app-id",
  client_secret: "secret",
  tenant_id: "tenant-id"
}
client = Msg.Client.new(credentials)

Exchanges credentials for access token via client credentials flow.

With access token string:

access_token = "eyJ0eXAi..."
client = Msg.Client.new(access_token)

Creates client with pre-existing access token (no token refresh).

2-arity: Token Provider or Refresh Token

Custom token provider (for testing):

token_provider = fn _creds -> "stub-token" end
client = Msg.Client.new(credentials, token_provider)

Refresh token with credentials:

client = Msg.Client.new(refresh_token, %{
  client_id: "app-id",
  client_secret: "secret",
  tenant_id: "tenant-id"
})

Automatically refreshes the access token using the provided refresh token. Returns {:error, term} if refresh fails.

See Msg.Auth for obtaining refresh tokens via OAuth authorization code flow.

Returns

Req.Request.t() - Configured HTTP client ready for Graph API calls, or {:error, term} - If token refresh fails (refresh token pattern only)