Home > Net >  Microsoft Graph API. Getting user activity
Microsoft Graph API. Getting user activity

Time:12-29

Currently I'm trying to create user activity from uwp application. But every time I encounter this response.

{
    "error": {
        "code": "AuthenticationError",
        "message": "Error authenticating with resource",
        "innerError": {
            "date": "2022-12-28T09:20:16",
            "request-id": "some id",
            "client-request-id": "some id"
        }
    }
}

Here is my c# code example. Request content string was taken from microsoft docs

public sealed class UserActivityProvider : IUserActivityProvider
{
    private const string activityId = "SendMessageUserActivity";
    private static HttpClient httpClient = new HttpClient();

    public UserActivityProvider()
    {
    }

    private async Task<string> GetAccessTokenAsync(Account account)
    {
        var accessToken = string.Empty;

        var publicClientApplication = PublicClientApplicationBuilder.Create(MicrosoftConstants.ClientId)
           .WithRedirectUri(MicrosoftConstants.RedirectUri)
           .Build();

        var scopes = new string[]
        {
            "UserActivity.ReadWrite.CreatedByApp"
        };

        AuthenticationResult? authToken = null;

        try
        {
            authToken = await publicClientApplication.AcquireTokenSilent(scopes, account.Email).ExecuteAsync();
        }
        catch (Exception)
        {
            authToken = await publicClientApplication.AcquireTokenInteractive(scopes).ExecuteAsync();
        }

        if (authToken != null)
        {
            accessToken = authToken.AccessToken;
        }

        return accessToken;
    }

    public async Task CreateUserActivityAsync(Account account, CreatingMessageUserActivityParameters userActivityParameters)
    {
        var accessToken = await GetAccessTokenAsync(account);
        if (accessToken != string.Empty)
        {
            var contentForCreatingActivity = new StringContent("{\r\n  \"appActivityId\": \"SendMessageUserActivity\",\r\n  \"activitySourceHost\": \"https://www.contoso.com\",\r\n  \"userTimezone\": \"Africa/Casablanca\",\r\n  \"appDisplayName\": \"Contoso, Ltd.\",\r\n  \"activationUrl\": \"https://www.contoso.com/article?id=12345\",\r\n  \"contentUrl\": \"https://www.contoso.com/article?id=12345\",\r\n  \"fallbackUrl\": \"https://www.contoso.com/article?id=12345\",\r\n  \"contentInfo\": {\r\n    \"@context\": \"https://schema.org\",\r\n    \"@type\": \"Article\",\r\n    \"author\": \"Jennifer Booth\",\r\n    \"name\": \"How to Tie a Reef Knot\"\r\n  },\r\n  \"visualElements\": {\r\n    \"attribution\": {\r\n      \"iconUrl\": \"https://www.contoso.com/icon\",\r\n      \"alternateText\": \"Contoso, Ltd.\",\r\n      \"addImageQuery\": false\r\n    },\r\n    \"description\": \"How to Tie a Reef Knot. A step-by-step visual guide to the art of nautical knot-tying.\",\r\n    \"backgroundColor\": \"#ff0000\",\r\n    \"displayText\": \"Contoso How-To: How to Tie a Reef Knot\",\r\n    \"content\": {\r\n      \"$schema\": \"https://adaptivecards.io/schemas/adaptive-card.json\",\r\n      \"type\": \"AdaptiveCard\",\r\n      \"body\": [\r\n        {\r\n          \"type\": \"TextBlock\",\r\n          \"text\": \"Contoso MainPage\"\r\n        }\r\n      ]\r\n    }\r\n  }\r\n}", Encoding.UTF8, "application/json");
            httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer "   accessToken);
            var response = await httpClient.PutAsync($"https://graph.microsoft.com/beta/me/activities/{activityId}", contentForCreatingActivity);
            var stringifiedResponse = await response.Content.ReadAsStringAsync();
        }
    }
}

And here is also get method for retrieving all activities and it's also return bad request

public async Task<string?> IsUserActivityExistsAsync(Account account)
{
    string? resultSubject = null;

    var accessToken = await GetAccessTokenAsync(account);
    if (accessToken != string.Empty)
    {
        httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer "   accessToken);
        var response = await httpClient.GetAsync("https://graph.microsoft.com/v1.0/me/activities");
        var stringifiedResponse = await response.Content.ReadAsStringAsync();
    }

    return resultSubject;
}

All articles referencing that I have to provide correct scope but I took that scope from official microsoft docs and there wouldn't be a mistake.

Response for getting activities

{
  "error": {
    "code": "UnknownError",
    "message": "{\"ErrorCode\":2,\"ErrorMessage\":\"Substrate operation failed. Url: https://substrate.office.com/api/v2.0/users('******(73)')/CurrentCollections('******(10)') Status: Unauthorized. Error Code: invalid_tenant Error Message: The tenant for tenant guid 'tenant' does not exist., SubstrateError: null\"}",
    "innerError": {
      "date": "2022-12-29T05:44:57",
      "request-id": "id",
      "client-request-id": "id"
    }
  }
}

Response for adding activities

{
  "error": {
    "code": "UnknownError",
    "message": "{\"ErrorCode\":35,\"ErrorMessage\":\"General error occurred. Contact product team.\"}",
    "innerError": {
      "date": "2022-12-29T05:59:02",
      "request-id": "id",
      "client-request-id": "id"
    }
  }
}

CodePudding user response:

Please make sure that UserActivity.ReadWrite.CreatedByApp MS Graph API permissions are assigned to your app in Azure AD as Delegated type (not Application)

UPDATED:

Not sure if you're using correct authentication provider, for delegated type (check options here https://learn.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS)

Try to acquire token by updating your code with the following changes

var publicClientApplication = PublicClientApplicationBuilder
    .Create(MicrosoftConstants.ClientId)
    .WithTenantId("YOUR_TENANT_ID")
    .Build();

and

var authToken  = await publicClientApplication
    .AcquireTokenByIntegratedWindowsAuth(scopes)
    .ExecuteAsync()
    .Result;

Note: Execute code under user account belonging to organization

CodePudding user response:

As you said you are getting empty data when you decoded the access token in jwt.ms , which means you are doing something wrong while acquiring access token , follow the doc to get token via Interactive provider , and then again check by decoding in jwt.ms .

var scopes = new[] { "User.Read" };

// Multi-tenant apps can use "common",
// single-tenant apps must use the tenant ID from the Azure portal
var tenantId = "common";

// Value from app registration
var clientId = "YOUR_CLIENT_ID";

// using Azure.Identity;
var options = new InteractiveBrowserCredentialOptions
{
    TenantId = tenantId,
    ClientId = clientId,
    AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
    // MUST be http://localhost or http://localhost:PORT
    // See https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/System-Browser-on-.Net-Core
    RedirectUri = new Uri("http://localhost"),
};

// https://learn.microsoft.com/dotnet/api/azure.identity.interactivebrowsercredential
var interactiveCredential = new InteractiveBrowserCredential(options);

var graphClient = new GraphServiceClient(interactiveCredential, scopes);
  • Related