Share via

Cannot refresh a token with admin consented scope for business central

Brett Wilson 20 Reputation points
2025-05-01T04:46:17.63+00:00

We’re trying to build an integration that connects with Microsoft Business Central for our customers.

This integration needs access to read and write data to Microsoft Business Central.

Our setup

  • We’ve created a multi-tenant application with Web authentication.
  • We’re authenticating the common endpoint as we don’t mind if personal or organisation companies use our app.
  • We’ve set up a client secret and use this when dealing with the /token endpoint.
  • Configured the application API permissions to request Dynamics API.ReadWrite.All and Microsoft Graph offline_access
  • We request the scopes https://api.businesscentral.dynamics.com/.default offline_access
  • These permissions have had admin consent, and we have done this both interactively using https://login.microsoftonline.com/common/adminconsent?client_id={application_client_id} and through the portal using Grant admin consent
  • We are able to successfully gain an access_token and refresh_token using the authorization code flow.
  • This access_token has the correct access that we expect and we can, for one day until it expires, access the business central company like we expect.

Where things go wrong is when we try to refresh the access_token using a valid, non-expired refresh token.

POST /common/oauth2/v2.0/token
Host: <https://login.microsoftonline.com>
Content-Type: application/x-www-form-urlencoded
Authorization: Basic xxx (client_id & client_secret)

refresh_token=xxx...
&grant_type=refresh_token

No matter what we do, we get

{ "error":"invalid_grant","error_description":"AADSTS65001: The user or administrator has not consented to use the application with ID 'xxxxxx-00ca-4a05-9d8c-9dd2da526591' named 'xxxxxx-Development'. Send an interactive authorization request for this user and resource. Trace ID: 1aa7c10f-f6f6-44a3-8e46-52f547d60c00 Correlation ID: e4df8738-4d07-4627-9676-929f076f5a7d Timestamp: 2025-05-01 03:56:40Z","error_codes":[65001],"timestamp":"2025-05-01 03:56:40Z","trace_id":"1aa7c10f-f6f6-44a3-8e46-52f547d60c00","correlation_id":"e4df8738-4d07-4627-9676-929f076f5a7d","suberror":"consent_required"}

What we’ve tried when refreshing the token

  • Calling with and without scopes with and without offline_access
  • Calling organizations endpoint and the {tenantId} endpoint instead of common
  • Revoking and regranting admin consent via the portal and the admin consent url.
  • Passing client_id and client_secret in the form body instead of as the basic auth header.
  • Trying permutations of business central scopes, but only /.default seems to work

One thing that stands out as incredibly strange is that if we remove the https://api.businesscentral.dynamics.com/.default scope, and only request openid offline_access, we are able to refresh the token, but we have no access to business central - which makes it useless to us. So this seems to be specific to our requesting scopes to business central.

Appreciate any help here!

Microsoft Security | Microsoft Entra | Microsoft Entra ID

Answer accepted by question author
  1. Akhilesh Vallamkonda 15,355 Reputation points Moderator
    2025-05-05T11:26:37.63+00:00

    Hi @Brett Wilson
    This type of error AADSTS65001 may occur when you are not giving the admin consent or using the wrong scope in the request.

    Based on the information you shared It seems you are giving the consent over the URL and portal.

    I noticed that you are using the https://api.businesscentral.dynamics.com/.default scope.
    which means it's client credential flow, and the same time the scop you have used the openid and offline_access are delegated permissions which means you are using 2 different permissions in one request,
    Delegated permissions like openid, offline_access are used when a user is present interactive login.

    Application permissions like https://api.businesscentral.dynamics.com/.default are used in client credentials flow no user context.
    For client credentials flow, use only .default scope. For authorization code flow, use delegated scopes like openid, offline_access, and specific API scopes.

    As mentioned above the error might cause due to wrong scope.
    To understand better may I know how you get the access token can you share the request which you used.

    Hope this helps. Do let us know if you any further queries by responding in the comments section.


    If this answers your query, do click Accept Answer and Yes for was this answer helpful. And, if you have any further query do let us know.

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Gianni 0 Reputation points
    2026-01-29T14:58:40.0633333+00:00

    I was in the exact situation as Brett, and quite frankly going a little crazy, until I found the alternative auth flow (Service-to-service authentication) that was required of us. Essentially permission is pre-granted when the app is manually installed and then your service can request access tokens asynchronously without user intervention.

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.