UnknownError for GraphApi creating PrintJob

Imran Pirmohamed 11 Reputation points
2021-12-08T21:23:57.257+00:00

I am trying to use GraphApi to create a print job. It seems to be working if grant_type is authorization_code but doesn't work if grant_type is password and the error I am getting is not really helpful. The user is a Printer Administrator and the registered app has all the required permissions with admin consent.

Error:

Status Code: Forbidden
Microsoft.Graph.ServiceException: Code: UnknownError
Inner error:
    AdditionalData:
    date: 2021-12-08T17:21:59
    request-id: 1bda2e07-7636-409a-a5dc-75c40bc64c2f
    client-request-id: 1bda2e07-7636-409a-a5dc-75c40bc64c2f
ClientRequestId: 1bda2e07-7636-409a-a5dc-75c40bc64c2f

   at Microsoft.Graph.HttpProvider.SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
   at Microsoft.Graph.BaseRequest.SendRequestAsync(Object serializableObject, CancellationToken cancellationToken, HttpCompletionOption completionOption)
   at Microsoft.Graph.BaseRequest.SendAsync[T](Object serializableObject, CancellationToken cancellationToken, HttpCompletionOption completionOption)
   at WebApplication1.Controllers.HomeController.PrintJob(Boolean useCredentials) 
   at WebApplication1.Controllers.HomeController.AuthRedirect(String code) 
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Logged|12_1(ControllerActionInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

Here's a Sample Code:

async Task Main()
{
    string tenantId = "TENANT ID GUID";
    string clientId = "REGISTERED APP CLIENT ID GUID";
    string clientSecret = "SECRET FROM REGISTERED APP";
    string printerId = "PRINTER ID GUID";
    string redirectUri = "https://localhost:44318/home/authredirect";
    string scope = "openid offline_access https://graph.microsoft.com/.default";
    string authorization_code = "AUTHORIZATION CODE FROM REDIRECT AFTER AUTHENTICATION";

    using var client = new HttpClient();
    var url = $"https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token";
    HttpResponseMessage res;

    bool useCredentials = true;

    if (useCredentials)
    {
        res = await client.PostAsync(url, new FormUrlEncodedContent(new Dictionary<string, string>
                {
                    { "client_id", clientId },
                    { "scope", scope },
                    { "username", "USER EMAIL ADDRESS" },
                    { "password", "USER PASSWORD" },
                    { "grant_type", "password" },
                    { "client_secret", clientSecret }
                }));
    }
    else
    {
        res = await client.PostAsync(url, new FormUrlEncodedContent(new Dictionary<string, string>
                {
                    { "client_id", clientId },
                    { "scope", scope },
                    { "code", authorization_code },
                    { "redirect_uri", redirectUri },
                    { "grant_type", "authorization_code" },
                    { "client_secret", clientSecret }
                }));
    }

    var content = await res.Content.ReadAsStringAsync();
    var token = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(content);
    var access_token = token["access_token"].ToString();

    GraphServiceClient _graphServiceClient = new GraphServiceClient(
        new DelegateAuthenticationProvider((request) =>
        {
            request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", access_token);
            return Task.FromResult(0);
        }));


    //Get user to test if calling GraphApi is successfull
    //THIS WORKS FOR BOTH GRANT TYPES
    var user = await _graphServiceClient.Me
        .Request()
        .GetAsync();

    //Create printJob 
    var printJob = new PrintJob { Configuration = new PrintJobConfiguration { Copies = 1, } };

    //THIS ONLY WORKS FOR authorization_code WORKFLOW
    var printJobResponse = await _graphServiceClient.Print.Printers[printerId].Jobs
        .Request()
        .AddAsync(printJob);
}
Microsoft Graph
Microsoft Graph
A Microsoft programmability model that exposes REST APIs and client libraries to access data on Microsoft 365 services.
10,715 questions
0 comments No comments
{count} votes