panva / openid-client

OAuth 2 / OpenID Connect Client API for JavaScript Runtimes
MIT License
1.83k stars 392 forks source link

Invalid grant_type when requesting for access_tokens #204

Closed Curtis1011 closed 4 years ago

Curtis1011 commented 4 years ago

Hi, I was testing the overall flow of openid with oidc-provider and openid-connect.When I was going through the step by step examples in oidc-provider 00-02, all of them works fine and I am able to get userinfo at the end.However I encountered a problem when I was trying to use the /03-oidc-views-accounts index.js.

I was able to obtain the code from the exchange, but I wasn't able to exchange for an access token and this error keeps popping up. (node:19535) UnhandledPromiseRejectionWarning: OPError: invalid_grant (grant request is invalid) at processResponse (/home/cchau/Desktop/auth_gateway/node_modules/openid-client/lib/helpers/process_response.js:39:13) at Client.grant (/home/cchau/Desktop/auth_gateway/node_modules/openid-client/lib/client.js:1068:26) at processTicksAndRejections (internal/process/task_queues.js:93:5) at async Client.callback (/home/cchau/Desktop/auth_gateway/node_modules/openid-client/lib/client.js:480:24)

After some digging, when I removed the findaccount:Account.findaccount in the config for the issuer on the server side code , I was able to exchange the code for an access token again.

I was wondering if this is the source of the problem or am I missing something?

Also when searching for a solution, I tried the solution provided by #198, But in both instances they gave me the same error. Thank you!

OIDC Server side:

const RedisAdapter = require('./redis_adapter');
const jwks = require('./jwks.json');

// simple account model for this application, user list is defined like so
const Account = require('./account');

const oidc = new Provider(`http://localhost:3000`, {
  adapter: RedisAdapter,
  //findAccount: Account.findAccount,
  clients: [

    {
      client_id: 'foo',
      client_secret: 'bar',
      grant_types: ['authorization_code'],
      redirect_uris: ['http://localhost:8080/cb'],

    }
  ],
  jwks,

  // oidc-provider only looks up the accounts by their ID when it has to read the claims,
  // passing it our Account model method is sufficient, it should return a Promise that resolves
  // with an object with accountId property and a claims method.
  //findAccount: Account.findAccount,

  // let's tell oidc-provider you also support the email scope, which will contain email and
  // email_verified claims
  claims: {
    openid: ['sub'],
    email: ['email', 'email_verified'],
  },

  // let's tell oidc-provider where our own interactions will be
  // setting a nested route is just good practice so that users
  // don't run into weird issues with multiple interactions open
  // at a time.
  interactionUrl(ctx) {
    return `/interaction/${ctx.oidc.uid}`;
  },
  features: {
    // disable the packaged interactions
    devInteractions: { enabled: false },

    introspection: { enabled: true },
    revocation: { enabled: true },
  },
});

oidc.proxy = true;

Open-Id Client side code:

const express = require('express');
const { Issuer, generators } = require('openid-client');
const app = express();

const codeVerifier = generators.codeVerifier();
const codeChallenge = generators.codeChallenge(codeVerifier);
const PORT = 8080;

let client;
Issuer.discover('http://localhost:3000/') // => Promise
    .then(function (localIssuer) {
        client = new localIssuer.Client({
            client_id: 'foo',
            client_secret: 'bar',
            redirect_uris: ['http://localhost:8080/cb'],

            response_types: ['code'],
        }); // => Client
    });

app.get('/start', (_req, res) => {
    const url = client.authorizationUrl({
        scope: 'openid',
        code_challenge_method: 'S256',
        code_challenge: codeChallenge,
    });
    console.log('Redirected to ', url);
    res.redirect(url);
});

app.get('/cb', (req, res) => {
    const params = client.callbackParams(req);
    client.callback('http://localhost:8080/cb', params, { code_verifier: codeVerifier }) // => Promise
        .then(function (tokenSet) {
            client.tokenSet = tokenSet;

            res.redirect('http://localhost:8080/userinfo');
        });
});

app.get('/userinfo', (_req, res) => {
    client.userinfo(client.tokenSet['access_token']) // => Promise
        .then(function (userinfo) {
            res.send({
                tokenSet: client.tokenSet,
                userinfo: userinfo,
            });
        });
});

app.listen(PORT, () => {
    console.log(`Client Server application is listening on port ${PORT}.`);
});
panva commented 4 years ago

It seems you either didn’t follow the OP steps exactly or introduced some OP misconfiguration.

I’m going to go ahead and close this since there’s no openid-client problem to be seen here and your next step should be debugging your OP.