IBM / openapi-to-graphql

Translate APIs described by OpenAPI Specifications (OAS) into GraphQL
https://developer.ibm.com/open/projects/openapi-to-graphql/
MIT License
1.61k stars 210 forks source link

JWT validation issues? #134

Open amnuts opened 5 years ago

amnuts commented 5 years ago

We're having an issue with - it seems - oasgraph when the OAS file has a JWT defined in it. The error we're getting is:

(node:4831) UnhandledPromiseRejectionWarning: AssertionError: path parameters must appear in the path
    at Assertion.fail (/app/node_modules/should/as-function.js:275:17)
    at Assertion.value (/app/node_modules/should/as-function.js:356:19)
    at checkParam (/app/node_modules/oas-validator/index.js:614:57)
    at checkPathItem (/app/node_modules/oas-validator/index.js:808:33)
    at /app/node_modules/oas-validator/index.js:1188:13
    at new Promise (<anonymous>)
    at Object.validateSync (/app/node_modules/oas-validator/index.js:915:28)
    at Object.<anonymous> (/app/node_modules/oasgraph/lib/oas_3_tools.js:43:38)
    at Generator.next (<anonymous>)
    at /app/node_modules/oasgraph/lib/oas_3_tools.js:11:71
(node:4831) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:4831) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
(node:4831) UnhandledPromiseRejectionWarning: Error: Invalid schema for JWT provided of type "undefined"
    at Object.getGraphQLType (/app/node_modules/oasgraph/lib/schema_builder.js:31:15)
    at getViewerAnyAuthOT (/app/node_modules/oasgraph/lib/auth_builder.js:146:37)
    at Object.createAndLoadViewer (/app/node_modules/oasgraph/lib/auth_builder.js:89:34)
    at /app/node_modules/oasgraph/lib/index.js:216:55
    at Generator.next (<anonymous>)
    at /app/node_modules/oasgraph/lib/index.js:11:71
    at new Promise (<anonymous>)
    at __awaiter (/app/node_modules/oasgraph/lib/index.js:7:12)
    at translateOpenApiToGraphQL (/app/node_modules/oasgraph/lib/index.js:79:12)
    at /app/node_modules/oasgraph/lib/index.js:67:40
(node:4831) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 4)

Our spec file looks fine to us; in the components section we have:

    "components": {
        "securitySchemes": {
            "JWT": {
                "type": "http",
                "scheme": "bearer",
                "bearerFormat": "JWT"
            }
        },

which seems right according to https://swagger.io/docs/specification/authentication/bearer-authentication/, and then within the paths we're using:

    "security": [
        {
             "JWT": []
         }
    ],

again, that seems correct according to the above url, but... errors! :-D

Does anyone have an idea? If it something we're doing wrong or need to adapt for oasgraph? Thanks!

ErikWittern commented 5 years ago

@amnuts From the error message (path parameters must appear in the path) and the origin of that message (...oas-validator/index.js:614:57) it seems this may not be directly related with JWT, but maybe with one of the operations being associated with a path parameter, but there is no use of that parameter in the URL path (i.e., the .../{path-parameter}/... part is missing).

In general, though, another question is whether OASGraph supports "scheme": "bearer", and I will have to check for that...

ErikWittern commented 5 years ago

It indeed seems OASGraph does not (yet) support the bearer scheme: https://github.com/strongloop/oasgraph/blob/6eb3c22603a1ff80217b652d8c0602203c72518a/packages/oasgraph/src/preprocessor.ts#L287

Alan-Cha commented 5 years ago

I will try to figure out why this error appeared but yes, we currently do not support this authentication scheme. We have support for OAuth2 tokens but not JWTs with the tokenJSONpath option. We are thinking on expanding on the option, allowing it to handle a wider range of tokens.

amnuts commented 5 years ago

Thanks, guys - I really appreciate your swift feedback!

brightecapital commented 5 years ago

love the library ! any eta on the jwt support ? pretty much just need to pass the jwtoken to the api endpoint which will then decide if its authenticated

Alan-Cha commented 5 years ago

@brightecapital Thank you for the compliment! Unfortunately, we haven't made any progress with JWT support, mostly been looking into other areas. Would you be interested in looking into issue and possibly submitting a PR to help jumpstart the process?

amnuts commented 5 years ago

@brightecapital we were in the same position as you - we just needed to pass on the JWT (from our gateway) to the other microservices for use - and the tokenJSONPath that @Alan-Cha mentioned actually worked for us.

How I set it up for us was adding a set of options to the gateway (we set that up using ExpressJS), which looked like:

    let oasOptions = {
        headers: {
            'X-Origin': 'GraphQL'
        },
        tokenJSONpath: '$.jwt'
    };

The headers part is arbitrary, it's the tokenJSONpath bit that's needed. Those options are then used when doing the OAS conversion:

const { schema, report } = await createGraphQlSchema(spec, oasOptions);

Once that was in there, I set up some middleware in the gateway that looked like:

    app.use(function (req, res, next) {
        // put the jwt back into the request so oasgraph can use it for
        // the context of each request via the tokenJSONPath option
        if (req.headers && req.headers.authorization) {
            req.jwt = req.headers.authorization.replace(/^Bearer /, '');
        }
        next();
    });

Once I did that, all other services that the gateway called had access to the JWT from the request.

Alan-Cha commented 5 years ago

@amnuts Thank you so much for replying! This is so helpful!!!

rodrigomf24 commented 4 years ago

Hi, I just spun up a loopback4 api with JWT authentication and noticed that with the following security spec openapi-to-graphql cli raises this error Cannot create data definition for invalid schema 'undefined'.

{
  bearerAuth: {
    type: 'http',
    scheme: 'bearer',
    bearerFormat: 'JWT',
  },
}

If I comment it out, it works great but I still get this error AssertionError: Could not dereference securityScheme bearerAuth.

this.api({
      openapi: '3.0.0',
      info: {title: pkg.name, version: pkg.version},
      paths: {},
      // components: {securitySchemes: SECURITY_SCHEME_SPEC},
      servers: [{url: '/'}],
    });

@amnuts do you have a sample of how you defined your components.securitySchemes? Has anyone been able to get this working with loopback4 with JWT auth?

Alan-Cha commented 4 years ago

@rodrigomf24 Are you sure that the first error is related to the bearerAuth securityScheme and not because of something else in the OAS? If you are, then I will need to figure out why this error is happening because it shouldn’t.

Again, I’m not too familiar with JWT so if @ErikWittern or @amnuts would like to weigh in, that would be greatly appreciated!

christheyounger commented 4 years ago

@amnuts do I understand correctly that you need to remove the security schemas and security requirements from your OAS to make your solution work? because otherwise I get a big fat UNSUPPORTED_HTTP_AUTH_SCHEME error, and/or the recently mentioned Cannot create data definition for invalid schema 'undefined' error

mbarton-cloudfm commented 4 years ago

Any movement on this? Would be super helpful to get this library playing ball with Bearer Auth. Unless anybody knows how to set up auth on loopback 4 with any other auth types supported by openapi-to-graphql 😀

Alan-Cha commented 4 years ago

@mbarton-cloudfm Unfortunately, no. There isn't anyone actively working on this. We are looking for some open source contributors who may be able to kick start the process.

jannyHou commented 4 years ago

@rodrigomf24 Your app probably has some controller endpoints secured by scheme bearerAuth, like this function

That's why the app complains:

If I comment it out, it works great but I still get this error AssertionError: Could not dereference securityScheme bearerAuth.