Microsoft Graph API - 'AuthenticationError ' (HTTP 400) on calls for GET /users/<user_id>/mailFolders/inbox/messageRules - outlook

We're running into an error with a specific Graph API endpoint, so any help or advice here is appreciated!
Problem:
We're seeing unexpected HTTP 400 errors on calls to fetch specific users' inbox rules, with code AuthenticationError.
Request:
https://graph.microsoft.com/v1.0/users/<USER_ID>/mailFolders/inbox/messageRules
Response:
{
"error": {
"code":"AuthenticationError",
"message":"Error authenticating with resource",
"innerError": {
"request-id":"44bbcef3-b8cd-4da0-978e-99955e55f3a7",
"date":"2020-05-19T14:55:52"
}
}
}
Note that we're only calling this method for non-external users where userType is member and onPremisesSyncEnabled is null. We're also supplying each user's ID as a parameter, rather than their user principal name.
Also - this example was pulled from our application, which is able to make calls to other Graph API endpoints without issue, including calls to fetch Users, Groups, Domains/Organizations, etc. This method does work for most of our clients but is failing in a few particular cases.
Here is a list of application scopes granted for the client:
AccessReview.Read.All
AuditLog.Read.All
Contacts.Read
Directory.Read.All
EduAdministration.Read.All
Group.Read.All
IdentityRiskEvent.Read.All
IdentityRiskyUser.Read.All
MailboxSettings.Read
Member.Read.Hidden
ProgramControl.Read.All
Reports.Read.All
SecurityEvents.Read.All
Sites.Read.All
User.Read.All
If there's any additional information we can provide to make this easier to troubleshoot, just let me know.
Thanks!

Related

How to run a query with Apollo GraphQL?

I am trying to figure out how to write a query in Apollo GraphQL.
I have a schema and have run the application in development mode. I have authenticated through the front end.
I expect that I should be able to follow this documentation and query the user.
I can see from the studio, that the Me query should be capable of checking for my first name (which I can see is recorded in the database), but when I press run in Apollo Studio, I get a null response to the query.
Is there an assumed step to get this working that needs to be taken before queries can be run? It gets worse when I try to do a query on the users table generally. That returns a not authenticated error (I have authenticated in the local environment in the dev app).
I'm struggling to connect the dots between the documentation that shows how this is expected to run queries and the starting point. I suspect that these documents have been prepared with the expectation that users know something fundamental about how to engage with them. I'm looking for disclosure as to what those assumptions might be. I can see from this question that there is a need for an authorisation header, (although my error is to do with authentication rather than authorisation). However, in my studio, the headers tab is empty. How do I populate it and what do I use to populate it?
I can see from the Apollo dev tool that it is trying to use a logged in query. I don't understand what drives this query in the Apollo Studio. Inside the localhost web app (which is running), I am logged in. When I try and run that query in the dev tools, the isLoggedIn (name of the query) is underlined, with an error explanation appearing that says:
Cannot query field "isLoggedIn" on type "Query".
The response shows:
{
"data": {}
}
I am lost for a starting point to find something to try and solve.
I think, based on a comment in this Odyssey tutorial, that the sandbox does not know how to connect to my psql data (not sure about this, but how could it know what queries I have, and not know which data has been stored in the attributes on the schema?). My env variables include my psql attributes and my prisma migrate is up to date. How can I let the sandbox know where the data is stored?
I am trying to learn using this boilerplate repo.
For my next attempt, I tried using the login mutation to generate a token, that I could try adding to the header. I don't know if it needs to be added under the name 'authorization' or 'token', so I made headers with both attribute names and added the same token to each of them.
I tried running the me and user query again, and get a mouthful of gibberish in the response.
The link in the response text goes to a page that has the following error message:
> <Error> <Code>NoSuchKey</Code> <Message>The specified key does not
> exist.</Message> </Error>
When I try going through the process of adding an APOLLO_KEY to my env variables and starting the server, I get an error that says "Unable to reach server". When I run the diagnose script on that error, I get:
Could not find any problems with the endpoint. Would you please to let
us know about this at explorer-feedback#apollographql.com 🙏
I created a new api key and tried again and am able to connect. I am able to run a login mutation and can return my first name inside that mutation, but I cannot do it from the me or user query - those queries still return the unauthenticated error response.
I have tried adding the authorization token to the header field both with and without "", and I have tried labelling that attribute as each of authorization, Authorization, token and then each of those inside "". None of them seems to make any difference to whether I can run a query. How can I find the name of the header token that Apollo Studio Explorer will accept?
I also tried the syntax suggested in this post, which is key Authorization and value "Bearer token" (there are double quotation marks around that string and a space between the word Bearer (capitalised) and the token string). There are no curly braces. That doesn't work either.
I have also tried expressing it as shown in this page of the Apollo documentation, which I think means that the key of the header value should be Authorization and the value should be the word Bearer, immediately followed by the token string generated in the output of the Login migration, inside {{ }}. When I try this, I get the same response as each of the other attempts described above.
There is a difference in the responses though, I get an unauthenticated response on the user query, and a null response on the me query.
One final strange observation: the studio returns the above error and null responses, but if I use the apollo client dev tools in the browser console, I can run the same Me query and get the result.
The user query still returns an unauthenticated error when I run it in the dev tools.
I'd also note that I can ask for the firstName attribute, inside the Login mutation, and receive them back in that response. However, I can't access them inside a Me query itself.
The next thing I investigated was how the resolver was managing the data. The boilerplate includes a resolver with:
import { AuthenticationError } from "apollo-server-express"
import { createMethodDecorator } from "type-graphql"
import { ResolverContext } from "../resolverContext"
export function UseAuth(roles?: string[]): any {
return createMethodDecorator<ResolverContext>(async ({ context: { req } }, next) => {
const argRoles = roles || []
if (req?.currentUser) {
if (argRoles.length === 0) return next()
if (argRoles.includes(req.currentUser.role)) return next()
throw new AuthenticationError("Not authorized")
} else {
throw new AuthenticationError("Not authenticated")
}
})
}
I wondered if maybe the role wasn't being considered. But I can see that it is inside the login mutation, but is not in a query.
Is there a 'for dummies' guide to getting started with apollo graphql?
I hope this spares someone some angst.
The format that works in Apollo Studio Explorer is
Key: Authorization
Value: Bearer[space][token]
There are no curly braces and no quotation marks in any of this. See this post for more discussion about this.

Calling Graph Api from Web Api doesn't return all user data

In my ASP.NET Core Web Api, I'm trying to call Graph API to retrieve the data of other users in the organization. I'm using the On Behalf Of flow. The bootstrap token is passed in from SPA client code.
In the Startup code, I have:
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration)
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph("https://graph.microsoft.com/beta", "user.read user.readbasic.all profile")
.AddInMemoryTokenCaches();
In the Controller's Action, I have:
_graphServiceClient.Users.Request()
.Filter($"mail eq 'someuser#myorg.com'")
.Select((user) => new {
DisplayName = user.DisplayName,
City = user.City,
Country = user.Country,
BusinessPhones = user.BusinessPhones
})
.Request()
.GetAsync();
However, at runtime, I only get the DisplayName value. I don't get the values of City, Country or BusinessPhones. They are al null.
When I tried the same query in Graph Explorer, I saw the values for all of them.
What am I missing?
First, your code snippet has an error that you wrote 2 .Request(), you should remove one.
Whatever flow you used are all generating an access token so that you can access the api, therefore when you got correct data from the api, that means you have a right setting in using the flow, so I think if there's any issue, it should locate at the part of calling api. Then I did some test in my side.
Could you pls check if you call the api directly, you can get the value of City, Country and BUsinessPhones these 3 properties? Per my test, when I call the api, I can get response like screenshot below and by default it's null
https://graph.microsoft.com/beta/users?$filter=mail eq
'tinywang#xxx.onmicrosoft.com'&$select=mail,city,country,DisplayName,BusinessPhones,userType,usageLocation
And when I followed this tutorial to call the api via sdk, I got the same result:
My idea is checking the response of calling the api first and if we can't find the issue, then could you pls provide the tutorial you followed to help reproduce the issue.

HTTP status code handling in GraphQL APIs

A lot of resources say, that GraphQL should always respond with a 200 status code, even when an error occurred:
https://www.graph.cool/docs/faq/api-eep0ugh1wa/#how-does-error-handling-work-with-graphcool
https://github.com/rmosolgo/graphql-ruby/issues/1130#issuecomment-347373937
https://blog.hasura.io/handling-graphql-hasura-errors-with-react/
Because GraphQL can return multiple responses in one response, this makes sense. When a user requests two resources in one request, and only has access to the first resource, you can send back the first resource and return a forbidden error for the second resource.
However, this is just something I figured out along the way reading docs of multiple GraphQL libraries and blog posts. I didn't find anything about HTTP status codes in the offical specs, here https://spec.graphql.org/ or here https://graphql.org/
So I still have a few questions left:
Is it ok to return a HTTP 500 status code if I have an unexpected server error?
Is it ok to return a HTTP 401 status code, if credentials are wrong?
Should I include the potential HTTP status code inside the errors key of the GraphQL response like this
{
"errors" => [{
"message" => "Graphql::Forbidden",
"locations" => [],
"extensions" => {
"error_class" => "Graphql::Forbidden", "status" => 403
}
}]
}
Should I match common errors like a wrong field name to the HTTP status code 400 Bad Request?
{
"errors" => [{
"message" => "Field 'foobar' doesn't exist on type 'UserConnection'",
"locations" => [{
"line" => 1,
"column" => 11
}],
"path" => ["query", "users", "foobar"],
"extensions" => {
"status" => 400, "code" => "undefinedField", "typeName" => "UserConnection", "fieldName" => "foobar"
}
}]
}
I'd be great if you could share your experiences / resources / best practises when handling HTTP status codes in GraphQL.
GraphQL is transport-agnostic. While GraphQL services are commonly web services that accept requests over HTTP, they can and do accept requests over other transports as well. In fact, a GraphQL service can execute queries with no network requests at all -- all it needs is a query, and, optionally, a variables object and operation name.
Because of this, the GraphQL spec isn't concerned with methods, status codes or anything else specific to HTTP (it only mentions HTTP when discussing serialization). Any practices with regard to these things are at best conventions that have either evolved over time or are simply artifacts from some of the original libraries that were written for GraphQL. As such, any kind of answer to your question is going to be mostly based on opinion.
That said, because your GraphQL service shouldn't care about how its queries are received, arguably there should be a separation between its code and whatever code is handling receiving the requests and sending back the responses (like an Express app in Node.js). In other words, we could say it's never ok for your resolver code to mutate things like the response's status code. This is the current thinking in the community and most libraries only return one of two codes -- 400 if the request itself is somehow invalid and 200 otherwise.
If your entire GraphQL endpoint is guarded by some authentication logic (say your server checks for some header value), then a GraphQL request might come back with a 401 status. But this is something we handle at the web server level, not as part of your schema. It's no different if something went terribly wrong with your web server code and it had to return a 500 status, or the nginx server sitting in front of your returned a 494 (Request header too large), etc.
Traditionally, errors encountered during execution should be thrown and that's it. GraphQL extensions can be used to provide additional context when the errors are collected and serialized -- the name of the error, the stack trace, etc. However, it makes little sense to include HTTP status codes with these errors when, again, the errors have nothing to do with HTTP. Doing so unnecessarily mixes unrelated concepts -- if you want to identify the type of error, you're better off using descriptive codes like GENERIC_SERVER, INVALID_INPUT, etc.
However, conventions around error handling are also changing. Some services want to better distinguish client errors from other execution errors. It's becoming more common to see validation errors or other errors that would be shown to the end user to be returned as part of the data instead of being treated like an execution error.
type Mutation {
login(username: String!, password: String!): LoginPayload!
}
type LoginPayload {
user: User
error: Error
}
You can see payload types like these in action with public APIs like Shopify's. A variant on this approach is to utilize unions to represent a number of possible responses.
type Mutation {
login(username: String!, password: String!): LoginPayload!
}
union LoginPayload = User | InvalidCredentialsError | ExceededLoginAttemptsError
The end result is that the client errors are strongly typed and easily distinguishable from other errors that the end user doesn't care about. There's a lot of benefits to adopting these sort of conventions, but whether they are the right fit for your server is ultimately up to you.

Verify graphql query

I'm building a simple platform using graphql as api gateway and a frontend that send some queries to this api, I'm blocked on how can I validate a query before run it to avoid malicious query to be ran. I was thinking to use persistgraphql but I just noticed that is now archived so I'm not sure if it's a good idea to use it, the second problem is that the api and the frontend are in 2 different repo so I didn't find yet a solution to whitelisting the query in the frontend and use this whitelist in the api...what's the best solution to whitelist a query with graphql?
If your concern is limiting access to certain fields based on who is making the request, then you should implement some kind of authorization strategy. You can populate the context with information about the logged in user and then use this information inside your resolvers for the fields you want to protect to determine whether the value of the field should be returned or not.
const resolvers = {
User: {
somePrivateField: (user, args, ctx) => {
// Make sure the request is from a logged in user and the user making the
// request is the same as the requested user OR the user is an admin
if (ctx.user && ( ctx.user.id === user.id || ctx.user.isAdmin )) {
return user.somePrivateField
}
// throw an error or just return null or undefined to resolve the field to
// null in the event authorization fails
}
}
}
More sophisticated strategies are possible using directives or existing libraries like graphql-shield.
Of course, certain fields that may exist on your database model -- like passwords -- should probably never be exposed in your API in the first place.

JSON API REST endpoint with permissions-restricted fields

JSON API REST endpoint with permissions-restricted fields
I am working on a JSON API-compliant REST api. Some endpoints contain fields that should be restricted (read-only or not available) for certain users.
What is the best way to architect the api to allow that certain users have access to certain fields, while others do not? By "best", I mean:
Most compliant with REST standards, ideally JSON API standards
Most clarity in terms of preventing bugs and confusion on behalf of clients consuming the API
I am considering the following options, each with their set of concerns/ questions. I would be more than grateful for any other solutions!
Option 1: Return null on restricted fields for users without permissions
Different data values would be returned per-user. Is this strictly anti-REST?
Lack of distinction between null meaning "null value" and null meaning "You don't have access to this"
In REST/ JSON API architecture, is it okay for an endpoint to return different data per user, based on permissions? I have the impression that this would be contrary to the spirit of resource-based REST architecture, but I could not find anything specific to point to in any doc or standard (e.g. JSON API). Also applies to Option 2.
Is there any paradigm for adding some sort of "You don't have access" flag in the resource's metadata?
Option 2: Exclude restricted fields entirely for users without permissions
Different data values would be returned per-user. Is this strictly anti-REST?
Possibility of "undefined" errors in client, when trying to retrieve field value
Option 3: Move restricted field(s) onto another endpoint, available as an ?include='field_name' relation for those with permission
Example: /api/entity includes attribute field "cost" which is only available to Admin users. Admin users can request cost data via GET /api/entity?include=cost. For all users, "cost" is exposed as a relation in the resource object, with a "type" and "id".
This is the option I am leaning toward. The main con here is endpoint clutter. I have a lot of relations that would need to be made into separate endpoints, simply to support a permissions-quarantined data on an already-existing endpoint.
In the JSON API specs, I am having trouble determining if it's ok for an endpoint to exist as a relation only, e.g. can we have /api/entity/1/cost, but NOT have a top-level api endpoint, /api/cost. My assumption is that if a resource has a "type" (in this case, the relation type being 'cost'), it also has to live on a top-level endpoint.
In this scenario, the client could get a 401: Unauthorized error response if a non-admin user tries to GET /api/entity?include=cost or GET /api/cost/:id
Note: I have already built a separate permissions schema so that the client can determine which CRUD privileges the user has, per top-level endpoint, before making any requests. Permission sets are indexed by resource type.
Any help on the matter would be very much appreciated! And if anything needs to be clarified, feel free to ask.
I would definitely not use undefined or null to indicate fields that the user is not allowed to see. To me, that feels like a lie and represents that the data is really not there. They would have to really know your API in order to get a grasp of what is really going on.
I would recommend something more like your 3rd option, except I would make it a different endpoint altogether. So in your example, the endpoints would be:
/api/entity/1/cost
and for admins
/api/admin/entity/1/cost
or something like that.
This way your server code for the admin endpoint could just be focused on authenticating this admin user and getting them back all the fields that they have visibility on. If a non admin user tries to hit that route, reject them with an unauthorized status code.
I'm not saying that you should not implement the GET param to be able to specify fields as well. You can if you want to, but I don't think it just won't be necessary in this case.

Resources