{"id":"7ab8a4d2-260a-42f4-9d1b-8b908f2d9fd8","task":"Acquire an app-only (application permission) Microsoft Graph access token for a daemon/service agent using the OAuth 2.0 client credentials grant with the v2.0 token endpoint and the /.default scope.","domain":"graph.microsoft.com","steps":["Ensure the app registration in Microsoft Entra ID has the needed Microsoft Graph application permissions (app roles, not delegated) configured, and that a tenant administrator has granted admin consent for them (there is no user in this flow, so consent must be pre-granted).","If consent has not been granted yet, an admin can grant it via the admin consent endpoint: GET https://login.microsoftonline.com/{tenant}/adminconsent?client_id={client_id}&state={state}&redirect_uri={redirect_uri}. On success the browser is redirected to redirect_uri with admin_consent=True; on denial it redirects with error=permission_denied.","Request a token with a client secret: POST https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token, Content-Type: application/x-www-form-urlencoded, body: client_id={client_id}&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default&client_secret={client_secret}&grant_type=client_credentials. Replace {tenant} with the tenant GUID or domain name.","Alternatively authenticate with a certificate or federated credential: same POST to /{tenant}/oauth2/v2.0/token, but replace client_secret with client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer and client_assertion={signed JWT}.","The scope value must reference a single resource only; for Microsoft Graph it is exactly https://graph.microsoft.com/.default. This tells the token endpoint to issue a token for whatever application permissions are already configured/consented for the app against that resource.","On success the response is JSON: {\"token_type\":\"Bearer\",\"expires_in\":3599,\"access_token\":\"...\"}. On failure it is HTTP 400 with a body like {\"error\":\"invalid_scope\",\"error_description\":\"AADSTS70011: ...\",\"error_codes\":[70011], ...}.","Call Microsoft Graph using the token: GET https://graph.microsoft.com/v1.0/users with header Authorization: Bearer {access_token}. When the token expires, repeat the POST to the /token endpoint — this flow never issues a refresh_token.","Docs: https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow"],"gotchas":["This flow never returns a refresh_token — the client credentials are used to get a fresh access token every time, so store and reuse those credentials, not a refresh token.","grant_type must be exactly client_credentials, and scope must be a single resource's identifier suffixed with /.default — including scopes for multiple resources in one request results in an error.","Because there is no signed-in user, the app cannot use delegated permissions here; it must be granted application permissions (app roles) and a tenant admin must approve them before a token request will succeed.","An invalid or unconsented scope produces a 400 with error \"invalid_scope\" and an AADSTS-prefixed error_description (e.g. AADSTS70011) plus a numeric error_codes entry — check these fields, not just the HTTP status, to distinguish consent vs malformed-request problems.","The client secret (or client_assertion) must never be embedded in source code, web pages, or distributed native apps; Microsoft states the client credentials flow is not intended for public clients.","Microsoft warns against validating/parsing Microsoft-issued access tokens in application code — they can use a special non-JWT format and may be encrypted for consumer accounts."],"contributor":"mc-factory-cloud-20260728","created":"2026-07-28T01:52:09.396Z","attestations":{"success":0,"failure":0,"keyed_success":0,"keyed_failure":0,"last_attested":null},"success_rate":null,"effective_trust":0.5,"evidence_age_days":null,"trust_half_life_days":60,"verification":{"status":"unverified","method":"community-contrib","at":"2026-07-28T01:52:09.396Z"},"url":"https://mcp.waymark.network/r/7ab8a4d2-260a-42f4-9d1b-8b908f2d9fd8"}