Search code examples
javarestauthenticationoauthdynamics-crm

Dynamics CRM REST OAuth Authentication Response 403 - The user is not a member of the organization


I am attempting to make a request to the Microsoft Dynamics CRM REST API. I am receiving a 403 response with message "The user is not a member of the organization." Could anyone advise where I am going wrong?

The Java Code I am using (I have removed ids/hostnames etc.):

public class CRMTesting {

    private static String TENANT_ID = "<tenant-id>";
    private static String POST_URL = "https://login.microsoftonline.com/" + TENANT_ID + "/oauth2/token";
    private static String CLIENT_ID = "<client-id>";
    private static String CLIENT_SECRET = "<client-secret>";

    public static void main(String[] args) throws Exception {
        String token = getToken();
        getAccounts(token);
    }

    public static String getAccounts(String token) throws MalformedURLException, IOException {

        CloseableHttpClient httpClient = HttpClients.createDefault();

        HttpGet httpGet = new HttpGet("https://<company>.crm4.dynamics.com/api/data/v8.2/accounts?$select=name&$top=3");
        httpGet.setHeader("Accept", "application/json");
        httpGet.setHeader("Authorization", "Bearer " + token);
        httpGet.setHeader("OData-MaxVersion", "4.0");
        httpGet.setHeader("OData-Version", "4.0");

        CloseableHttpResponse httpResponse = httpClient.execute(httpGet);

        System.out.println("Response Status Code... " + httpResponse.getStatusLine().getStatusCode());

        BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));

        String inputLine;
        StringBuffer response = new StringBuffer();

        while ((inputLine = reader.readLine()) != null) {
            response.append(inputLine);
        }
        reader.close();
        httpClient.close();

        System.out.println(response.toString());

        // Extract the token from the json response
        final ObjectMapper mapper = new ObjectMapper();
        final JsonNode actualObj = mapper.readTree(response.toString());

        return actualObj.get("access_token").asText();

    }

    public static String getToken() throws MalformedURLException, IOException {
        // create headers

        CloseableHttpClient httpClient = HttpClients.createDefault();

        HttpPost httpPost = new HttpPost(POST_URL);
        httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
        nvps.add(new BasicNameValuePair("grant_type", "client_credentials"));
        nvps.add(new BasicNameValuePair("resource", "https://<company>.crm4.dynamics.com"));
        nvps.add(new BasicNameValuePair("client_id", CLIENT_ID));
        nvps.add(new BasicNameValuePair("client_secret", CLIENT_SECRET));
        httpPost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));

        CloseableHttpResponse httpResponse = httpClient.execute(httpPost);

        BufferedReader reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));

        String inputLine;
        StringBuffer response = new StringBuffer();

        while ((inputLine = reader.readLine()) != null) {
            response.append(inputLine);
        }
        reader.close();
        httpClient.close();

        System.out.println(response.toString());

        // Extract the token from the json response
        final ObjectMapper mapper = new ObjectMapper();
        final JsonNode actualObj = mapper.readTree(response.toString());

        return actualObj.get("access_token").asText();

    }

}

The 403 response:

{"token_type":"Bearer","expires_in":"3599","ext_expires_in":"3599","expires_on":"1698847590","not_before":"1698843690","resource":"https://<company>.crm4.dynamics.com","access_token":"<access-token>"}
Response Status Code... 403
{"error":{"code":"0x80072560","message":"The user is not a member of the organization."}}

I have tried many things such as adding a "scope" parameter in the token request.. using a different POST url "/oauth2/v2.0/token".. using java.net.HttpURLConnection rather than apache CloseableHttpClient.. etc. however I am yet to find a solution.

Any help would be great!

Thanks


Solution

  • If you've got an Application User in Azure, with a Tenant Id and a Client ID, you have to add that user to your CRM instance, and then give it security roles

    This will take you through the process of adding your Application User to a Business Unit, and giving it some security roles.

    Once you've done that, try your code again

    Refer to https://learn.microsoft.com/en-gb/power-platform/admin/manage-application-users?WT.mc_id=ppac_inproduct_settings