Search code examples
javaazuremicrosoft-graph-api

Microsoft Graph API returns invalid_role_scope_combination when trying to get a profile photo


I need to get profile photos from MS Graph API and upload them to Azure Blob storage.

I am doing this with MS Graph Java SDK. Here us the code for retrieving the photo InputStream:

InputStream photoInputStream = graphServiceClient.users().byUserId(adUser.getId()).photo().content().get();

When this call is made, I get the following exception:

com.microsoft.graph.models.odataerrors.ODataError: invalid_role_scope_combination
    at com.microsoft.graph.models.odataerrors.ODataError.createFromDiscriminatorValue(ODataError.java:36) ~[microsoft-graph-6.4.0.jar:na]
    at com.microsoft.kiota.serialization.JsonParseNode.getObjectValue(JsonParseNode.java:210) ~[microsoft-kiota-serialization-json-1.0.4.jar:na]
    at com.microsoft.kiota.http.OkHttpRequestAdapter.lambda$throwIfFailedResponse$0(OkHttpRequestAdapter.java:672) ~[microsoft-kiota-http-okHttp-1.0.4.jar:na]
    at com.microsoft.kiota.ApiExceptionBuilder.<init>(ApiExceptionBuilder.java:26) ~[microsoft-kiota-abstractions-1.0.4.jar:na]
    at com.microsoft.kiota.http.OkHttpRequestAdapter.throwIfFailedResponse(OkHttpRequestAdapter.java:671) ~[microsoft-kiota-http-okHttp-1.0.4.jar:na]
    at com.microsoft.kiota.http.OkHttpRequestAdapter.sendPrimitive(OkHttpRequestAdapter.java:341) ~[microsoft-kiota-http-okHttp-1.0.4.jar:na]
    at com.microsoft.graph.users.item.photo.value.ContentRequestBuilder.get(ContentRequestBuilder.java:60) ~[microsoft-graph-6.4.0.jar:na]
    at com.microsoft.graph.users.item.photo.value.ContentRequestBuilder.get(ContentRequestBuilder.java:46) ~[microsoft-graph-6.4.0.jar:na]
...

I have added the following permissions to application registration: enter image description here

Here is the code for configuring MS Graph API credentials if this helps:

private static final String DEFAULT_MS_GRAPH_SCOPE = "https://graph.microsoft.com/.default";

@Bean
public GraphServiceClient graphServiceClient() {
    ClientSecretCredential clientSecretCredential = new ClientSecretCredentialBuilder()
            .clientId(clientId)
            .clientSecret(clientSecret)
            .tenantId(tenantId)
            .build();

    return new GraphServiceClient(clientSecretCredential, DEFAULT_MS_GRAPH_SCOPE);
}

Solution

  • I registered one Azure AD application and granted User.ReadBasic.All permission of Application type as below:

    enter image description here

    To retrieve the profile image of user and upload it to Azure blob storage, you can make use of below modified java code:

    import com.azure.identity.ClientSecretCredential;
    import com.azure.identity.ClientSecretCredentialBuilder;
    import com.microsoft.graph.authentication.TokenCredentialAuthProvider;
    import com.microsoft.graph.models.User;
    import com.microsoft.graph.requests.GraphServiceClient;
    
    import java.io.ByteArrayInputStream;
    import java.io.InputStream;
    import java.util.Arrays;
    import java.util.List;
    
    import com.azure.storage.blob.BlobClient;
    import com.azure.storage.blob.BlobClientBuilder;
    import com.azure.storage.blob.BlobContainerClient;
    import com.azure.storage.blob.BlobContainerClientBuilder;
    
    public class AzureADUserAuth {
        final String clientId = "appId";
        final String tenantId = "tenantId";
        final String clientSecret = "secret";
        final List<String> scopes = Arrays.asList("https://graph.microsoft.com/.default");
    
        // Azure Blob Storage settings
        final String connectionString = "storacc_connection_string";
        final String containerName = "profile-photos"; // Name of your blob container
    
        public static void main(String[] args) {
            try {
                AzureADUserAuth azureADUserAuth = new AzureADUserAuth();
                azureADUserAuth.fetchAndUploadProfilePhoto();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void fetchAndUploadProfilePhoto() throws Exception {
            // Authenticate with Azure AD
            ClientSecretCredential credential = new ClientSecretCredentialBuilder()
                    .clientId(clientId).tenantId(tenantId).clientSecret(clientSecret)
                    .build();
    
            if (null == scopes || null == credential) {
                throw new Exception("Unexpected error");
            }
    
            TokenCredentialAuthProvider authProvider = new TokenCredentialAuthProvider(scopes, credential);
            GraphServiceClient graphClient = GraphServiceClient.builder().authenticationProvider(authProvider).buildClient();
    
            // Fetch user profile photo as InputStream
            InputStream profilePhotoStream = graphClient.users("userId")
                    .photo()
                    .content()
                    .buildRequest()
                    .get();
    
            // Read the profile photo content into a byte array
            byte[] photoBytes = profilePhotoStream.readAllBytes();
    
            // Create InputStream from byte array
            InputStream inputStream = new ByteArrayInputStream(photoBytes);
    
            // Upload profile photo to Azure Blob Storage
            BlobContainerClient containerClient = new BlobContainerClientBuilder()
                    .connectionString(connectionString)
                    .containerName(containerName)
                    .buildClient();
    
            BlobClient blobClient = containerClient.getBlobClient("profile_photo.jpg");
            blobClient.upload(inputStream, photoBytes.length, true);
    
            // Close the InputStream when done
            profilePhotoStream.close();
    
            System.out.println("\nProfile photo uploaded to Azure Blob Storage.\n");
        }
    }
    

    Response:

    enter image description here

    To confirm that, I checked the same in Azure Storage account blob container where profile photo uploaded successfully like this:

    enter image description here