Apollo Server executeOperation with authorization headers
Asked Answered
S

2

9

How do we pass headers to Apollo server executeOperation in tests?

There is mention about passing a headers object here

I'm trying to pass an auth header with or without a JWT token to test access control.

const result = await server.executeOperation({ query: query, http: { headers: { authorization: "" } } })

// Type '{ authorization: string; }' is not assignable to type 'Headers'.
//  Object literal may only specify known properties, and 'authorization' does not exist in type 'Headers'.ts(2322)

This results in a type error. There is a Headers class defined in the Apollo server types in fetch.d.ts but I'm un able to import to instantiate it.

Using "apollo-server": "^2.25.2". Any hints or links to get this going?


Update: as a work around I'm decrypting and decoding the JWT in the server context and passing an authenticated user around in there. Then I'm able to mock the whole context and create a new test server with the mocked context. It'd be nice to be able to user headers for more production like experience but this works for now.

import { mockDeep, mockReset } from 'jest-mock-extended'

interface Context {
  prisma: PrismaClient
  user: () => User|null
}

export const context = mockDeep<Context>()

export const testServer = new ApolloServer({
  typeDefs,
  resolvers,
  context
});

// ...

context.user.mockReturnValue({
  id: 1,
  name: "Foo",
  slug: "foo",
})

const res = await testServer.executeOperation({ query: query })
Stanfordstang answered 15/8, 2021 at 22:25 Comment(1)
docs are very thin on this. Also seeking some infoChuu
S
3

Apollo Server now supports a second parameter for executeOperation. It is possible to provide the parameters used in the context function.

  const result = await server.executeOperation(
    { query: query },
    { req: { headers: { authorization: '...' } } }
  );

Note: With Typescript, it will complain but you can cast it in any and avoid building the whole express.Request type.

Tested with [email protected]

The other solution works but I find this one convenient. If you mock the token parsing, you can easily simulate calls from different users.


Snowmobile answered 10/8, 2022 at 1:9 Comment(1)
Thanks for the notification. I'll give it a tryStanfordstang
B
0

To solve this, I have created a 'fake' request object with the already decrypted JWT token that I used to initialize my third party auth object (keycloak) and pass to the apollo context. I need to initialize the keycloak object because I have authentication schema directives that require the keycloak object to be initialized.

 const req = {
      kauth: {
        grant: {
          access_token: {
            isExpired: () => {
              return false;
            },
            token: "abc",
            content: {
              email: "[email protected]",
              resource_access: {
                "my-api": {
                  roles: ["admin"],
                },
              },
            },
          },
        },
      },
    };

    server = new ApolloServer({
      schema,
      resolvers,
      dataSources: () => ({
        users,
      }),
      context: () => {
        return { kauth: new KeycloakContext({ req }) };
      },
    });
  });

Still, I would like a solution that is more native to apollo and not a work around.

Bushtit answered 15/5, 2022 at 5:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.