Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(auth): Allows RedwoodAuthCurrentUserQuery when using Auth, GraphQL and Trusted Documents #10817

Merged
merged 4 commits into from
Jun 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .changesets/10817.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
fix(auth): Allows RedwoodAuthCurrentUserQuery when using Auth, GraphQL and Trusted Documents (#10817) by @dthyresson

This PR allows authentication to function as expected when using Trusted Documents.

See issue #10816 above for more detail.

One way to solve is to allow an arbitrary ad-hoc query -- but just a very narrow and well-defined (aka trusted so-to-speak) one.

The plgin for persisted operations lets one define what can bypass trusted docs hash id checks: https://the-guild.dev/graphql/yoga-server/docs/features/persisted-operations#allowing-arbitrary-graphql-operations

So, we can use that in the useTrustedDocuments plugin to just allow that specific request.

const REDWOOD__AUTH_GET_CURRENT_USER_QUERY =
'{"query":"query __REDWOOD__AUTH_GET_CURRENT_USER { redwood { currentUser } }"}'
When using Redwood Auth, we want to allow the known, trusted redwood.currentUser query to be executed without a persisted operation.

This is because the currentUser query is a special case that is used to get the current user from the auth provider.

We'll check if the request is for the currentUser query and has the correct headers which are set by the useCurrentUser hook in the auth package.

The usePersistedOperations plugin relies on this function to determine if a request should be allowed to execute via its allowArbitraryOperations option.

By checking for that very exact string, and that there is a content type header, an auth-provider header and an authorization header then we can allow this to execute.

The auth provider will still be used by the apes getCurrentUser resolver to determine if the credentials whatever they are are valid.
33 changes: 33 additions & 0 deletions packages/graphql-server/src/plugins/useRedwoodTrustedDocuments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,36 @@ export type RedwoodTrustedDocumentOptions = {
customErrors?: CustomPersistedQueryErrors
}

const REDWOOD__AUTH_GET_CURRENT_USER_QUERY =
'{"query":"query __REDWOOD__AUTH_GET_CURRENT_USER { redwood { currentUser } }"}'

/**
* When using Redwood Auth, we want to allow the known, trusted `redwood.currentUser` query to be
* executed without a persisted operation.
*
* This is because the `currentUser` query is a special case that is used to get
* the current user from the auth provider.
*
* This function checks if the request is for the `currentUser` query and has the correct headers
* which are set by the useCurrentUser hook in the auth package.
*
* The usePersistedOperations plugin relies on this function to determine if a request
* should be allowed to execute via its allowArbitraryOperations option.
*/
const allowRedwoodAuthCurrentUserQuery = async (request: Request) => {
const headers = request.headers
const hasContentType = headers.get('content-type') === 'application/json'
const hasAuthProvider = !!headers.get('auth-provider')
const hasAuthorization = !!headers.get('authorization')
const hasAllowedHeaders =
hasContentType && hasAuthProvider && hasAuthorization

const query = await request.text()
const hasAllowedQuery = query === REDWOOD__AUTH_GET_CURRENT_USER_QUERY

return hasAllowedHeaders && hasAllowedQuery
}

export const useRedwoodTrustedDocuments = (
options: RedwoodTrustedDocumentOptions,
): Plugin<RedwoodGraphQLContext> => {
Expand All @@ -21,5 +51,8 @@ export const useRedwoodTrustedDocuments = (
getPersistedOperation(sha256Hash: string) {
return options.store[sha256Hash]
},
allowArbitraryOperations: async (request) => {
return allowRedwoodAuthCurrentUserQuery(request)
},
})
}
Loading