aerogear / keycloak-connect-graphql

Add Keyloak Authentication and Authorization to your GraphQL server.
Apache License 2.0
155 stars 22 forks source link

kauth.accessToken resolving when debugging, but not when compiled #126

Closed harrylepotter-win closed 3 years ago

harrylepotter-win commented 3 years ago

I am experiencing a bizarre issue when attempting to use the keycloak context. In my environment, i have code similar to:

const server = new ApolloServer({
    schema: schema,
    context: async ({ req }) => {
      //@ts-expect-error
      let kauth = new KeycloakContext({ req }, keycloak);

      console.log('kauth access token', kauth.accessToken);
      return {
        kauth: kauth
      }
    }
  });

When running this in vscode's typescript debugger environment, this appears to work perfectly:

kauth access token Token {token: 'eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkI…QevwDANz3Itd

However, when compiled or in live mode, kauth.accessToken is not resolved:

kauth access token undefined

...Which in-turn is causing downstream issues on my resolvers when trying to access the accessToken I'm wondering if perhaps there's a promise not completing in time somewhere? Wish i could provide more information, but unfortunately i'm scratching my head trying to figure out why one environment works and another does not.... Is there any way to force Keycloak context to wait? Perhaps the issue is upstream with my keycloak middleware?

main code body looks like the following:

const keycloak = initKeyCloak();

app.use('/graphql', keycloak.middleware());

async function startApolloServer() {

  const client = await new DwnKeycloakClient().ready();
  const roles = new RoleManager(client, 'aphex');
  const users = new UserManager(client, 'aphex');
  const resolvers = {};

  //merges the type defs from roles, users (and presumedly future services)
  //into a single GraphQL endpoint
  let schema = stitchSchemas({
    typeDefs: [KeycloakTypeDefs, users.typeDefs, roles.typeDefs],
    resolvers: [roles.resolvers, users.resolvers],
    schemaDirectives: KeycloakSchemaDirectives
  });

  const server = new ApolloServer({
    schema: schema,
    context: async ({ req }) => {
      //@ts-expect-error
      let kauth = new KeycloakContext({ req }, keycloak);

      console.log('kauth access token', kauth.accessToken);
      return {
        kauth: kauth
      }
    }
  });

  await server.start();
  server.applyMiddleware({ app });
  app.listen(PORT, () => {
    console.log(`⚡️[server]: Server is running at https://localhost:${PORT}${server.graphqlPath}`);
  });

};

startApolloServer().then(() => {
  console.log(`Server started with GraphQL`);
});
wtrocki commented 3 years ago

This sounds like issue with your bundler not working with our repository or something like it.

We rely on keycloak.js and commonjs format

On PTO so replies will be delayed.

harrylepotter-win commented 3 years ago

Thanks for the reply @wtrocki

hmm... Both debug mode and the compiled code i'm running rely on the same tsconfig:

{
    "compilerOptions": {
      "lib": ["es2020"],
      "target": "es6",
      "module": "commonjs",
      "rootDir": "./src",
      "outDir": "./dist",
      "esModuleInterop": true,
      "strict": true,
      "sourceMap": true
    }
}

i've tried changing target to basically every value (es6, es2018, es2020, esnext) but to no avail.

wtrocki commented 3 years ago

oh.. I see problem now in your code snippet. Apply middleware is done after server started - Moving to the top will solve it.

wtrocki commented 3 years ago

Code:



async function startApolloServer() {
  const keycloak = initKeyCloak();
  app.use('/graphql', keycloak.middleware());

  // What is this?
  const client = await new DwnKeycloakClient().ready();
  const roles = new RoleManager(client, 'aphex');
  const users = new UserManager(client, 'aphex');
  const resolvers = {};

  //merges the type defs from roles, users (and presumedly future services)
  //into a single GraphQL endpoint
  let schema = stitchSchemas({
    typeDefs: [KeycloakTypeDefs, users.typeDefs, roles.typeDefs],
    resolvers: [roles.resolvers, users.resolvers],
    schemaDirectives: KeycloakSchemaDirectives
  });

  const server = new ApolloServer({
    schema: schema,
    context: async ({ req }) => {
      //@ts-expect-error
      let kauth = new KeycloakContext({ req }, keycloak);

      console.log('kauth access token', kauth.accessToken);
      return {
        kauth: kauth
      }
    }
  });

   server.applyMiddleware({ app });

  await server.start();

  app.listen(PORT, () => {
    console.log(`⚡️[server]: Server is running at https://localhost:${PORT}${server.graphqlPath}`);
  });

};

startApolloServer().then(() => {
  console.log(`Server started with GraphQL`);
});
harrylepotter-win commented 3 years ago

Think that might indicate something when i changed per your rec:

Error: called start() with surprising state invoking serverWillStart
    at ApolloServer.<anonymous> (/Users/bdavey/dev/evolution/framework/dwn_aphex/aphex-server/node_modules/apollo-server-core/src/ApolloServer.ts:511:13)
    at Generator.next (<anonymous>)
    at /Users/bdavey/dev/evolution/framework/dwn_aphex/aphex-server/node_modules/apollo-server-core/dist/ApolloServer.js:8:71
    at new Promise (<anonymous>)
    at __awaiter (/Users/bdavey/dev/evolution/framework/dwn_aphex/aphex-server/node_modules/apollo-server-core/dist/ApolloServer.js:4:12)
[nodemon] app crashed - waiting for file changes before starting...

does that possibly suggest the middleware isn't properly setup when i attempt to invoke it via app?

wtrocki commented 3 years ago

My recomendation would be to start with:

https://github.com/aerogear/keycloak-connect-graphql/blob/master/examples/basic.js

Then try to apply your specific code.

harrylepotter-win commented 3 years ago

my bad. Was an uninitialized environment variable that was being used globally. Sorry for bothering you!

Amazing library btw!

c0bra commented 3 years ago

@wtrocki we're having this problem on our project, but it's some weird case where it only happens locally. In our staging environment, kauth.accessToken is decoded and available.

Locally, even using our production build it's always undefined and I'm not able to track down why.

wtrocki commented 3 years ago

Do you use the same client information locally and on stage?

proftom commented 2 years ago

my bad. Was an uninitialized environment variable that was being used globally. Sorry for bothering you!

Amazing library btw!

having trouble getting accessToken to be anything other than undefined. what was the uninitialized environment variable, was it keycloak related?