parse-community / Parse-SDK-JS

The JavaScript SDK for Parse Platform
https://parseplatform.org
Apache License 2.0
1.32k stars 597 forks source link

Pass Bearer token as query request option #1528

Open stephannielsen opened 2 years ago

stephannielsen commented 2 years ago

New Feature / Enhancement Checklist

Current Limitation

We are using JWT based authentication (https://github.com/parse-community/parse-server/pull/6411) on server side together. Currently, we do not create Parse Sessions anymore as they are not needed. We are using cloud functions, which works fine with the JWT approach but one downside is that it is not easy to run the cloud function in the user context because we have no sessionToken to pass to the SDK. We could use CoreManager to set the Auth token, but it is set globally which we want to avoid in Cloud context where requests are made in multiple user contexts. If we don't reset the code properly, another request might use the token from another user...not to speak of concurrency issues in general with that approach. I proposed request interceptors as a new feature in #1449 which would tackle the same problem but now thought of a different way which would make it especially easier for cloud functions.

Feature / Enhancement Description

It is possible to pass a session token to the Parse.Query call via options:

myQuery.save(null, { sessionToken: 'abc' });

This token is added to the request as a X-Parse-Session-Token header and interpreted on server side. The idea is now to add another option, authorizationHeader to options which is then simply added as Authoriation header to the request. Parse Server would then validate this bearer token like a usual request and use the JWT functionality.

If I am not mistaken, the change would be fairly simple and only touch RestController.js + tests.

Example Use Case

myQuery.save(null, { authorization: 'Bearer abc123' });

This would allow us in Cloud functions to simply pass the auth header of the request along to the new request.

Alternatives / Workarounds

3rd Party References

parse-github-assistant[bot] commented 2 years ago

Thanks for opening this issue!

stephannielsen commented 2 years ago

I am willing to provide a PR for this, if this seems like a good idea to add, @mtrezza ?

stephannielsen commented 2 years ago

Another idea would be to add customHeaders as allowed option which can again be a map of header name to header value and the SDK simply adds all custom headers to the request.

myQuery.save(null, { customHeaders: { Authorization: 'Bearer abc123', 'X-Something': 'Whooops' } });
mtrezza commented 2 years ago

How does https://github.com/parse-community/parse-server/pull/7079 play into this? I think any auth-related change should be seen in that context, because that PR will likely get merged soon.

stephannielsen commented 2 years ago

To be honest, I can't put the two into a directly related context. I am not entirely sure what https://github.com/parse-community/parse-server/pull/7079 solves in this regard. Maybe @Moumouls can weigh in on this. But given the latest comments on the PR, it also didn't look like it's going to get merged soon?

The idea described here is about adding the Authorization HTTP header to a Parse Query call. As an auth token, like a JWT Bearer token, is short lived, it changes quite frequently, potentially up to every request. The existing solution to set the Auth info via CoreManager is cumbersome to use as it sets those values globally and you have to reset them after the request to not reuse it accidentally - and potentially leak it / use it in the wrong context (cloud context). The proposed change does not require any change in parse-server - the SDK simply adds another header to this particular request. The SDK does not know why or what it is for, and it fully depends on server side implementation how to handle it. parse-server has - to my knowledge - no default handling for Authorization header so this would have no affect if user sets it but has no corresponding server side implementation.

As proposed in my other comment, I am open for implementing this in a more general fashion as customHeaders option. Then it is not directly connected to auth topics - just a way to pass custom HTTP headers to Parse Query calls.

mtrezza commented 2 years ago

it is not directly connected to auth topics - just a way to pass custom HTTP headers to Parse Query calls.

So it's like https://github.com/parse-community/Parse-SDK-JS/issues/1014 but you want to set custom headers as a request (query) parameter? If so, I think we can leverage existing logic (e.g. allow-listing custom headers server side).

stephannielsen commented 2 years ago

Yes. It is like #1014 but I absolutely want to avoid using CoreManager for this in Cloud functions. The server-side is not really affected by this, accept that the header you sent must be in the list of allowed headers for CORS - but that's always the case for any custom header...

Our users authenticate via JWT token (provided by an Azure service) and Parse.User objects have no related session in our setup - as the JWT token is validated on each request. This works fine to to restrict access to cloud functions. But now, we want to run queries via the JS SDK in the cloud function within the user context, because we also want to use ACLs. Normally, you could pass the user's session token as option, which is then added as a HTTP header by the SDK for the request. But we do not have a session token. It would work fine though if I could simply add the user's JWT token (which is available in the cloud function request) to the HTTP call of the query inside the cloud function - just like the session token.

As the user context is different for each Cloud function run, we don't want to user CoreManager to set the token before running a query - because we would have to reset this every time after the query. If you forget to reset the token, the token of user A might be added to a request of user B - because it is set globally in the JS SDK. It should only be used on that one query request (or if we use batch request like findAll, on all requests involved).

Probably, I could also use the user's JWT token as session token and implement a workaround on server side with a request interceptor/middleware that takes x-parse-session-token value and adds it as authorization header - but that's just a hack to work around Parse missing functionality here.

mtrezza commented 2 years ago

Got it I think it makes sense.

mtrezza commented 2 years ago

Got it I think it makes sense.

stephannielsen commented 2 years ago

Cool, which proposal do you see more fitting? In #1529 I chose the simple way now but even supporting any custom headers wouldn't be much work. I am just not sure if it's really needed here for now.

mtrezza commented 2 years ago

If a more general custom header option would make a specific custom auth header option unnecessary, we should probably go for the general option:

stephannielsen commented 2 years ago

Yep, I see the benefits. I will update the PR accordingly.

mtrezza commented 2 years ago

Amazing, if you need any support, please request!