panva / openid-client

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

Update README.md #198

Closed lin826 closed 5 years ago

lin826 commented 5 years ago

Make sure the string is going to be recognized as code_verifier.

By running quick start in README.md, the grant failed without this setting.


Example Repo: https://github.com/lin826/auth-toy

Provider Server's Code

const express = require('express');
const Provider = require('oidc-provider');

const { PORT = 3000, ISSUER = `http://localhost:${PORT}` } = process.env;

const configuration = {
  // ... see available options /docs
  clients: [{
    client_id: 'code_foo',
    client_secret: 'bar',
    grant_types: ['refresh_token', 'authorization_code'],
    redirect_uris: ['https://127.0.0.1:8080/code_cb'],
    client_name: 'foo has a name',
    contacts: ['foo@email.com'],
    // + other client properties
  }],
};

const provider = new Provider(ISSUER, configuration);
const app = express();

app.use(provider.callback);

module.exports = app.listen(PORT, () => {
  console.log(`application is listening on port ${PORT}, check its /.well-known/openid-configuration`);
});

Client Server's Code


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

const { PORT = 8080, ISSUER = `https://127.0.0.1:${PORT}` } = process.env;

let code_client;
Issuer.discover('http://localhost:3000/.well-known/openid-configuration') // => Promise
.then(function (localIssuer) {
  code_client = new localIssuer.Client({
    client_id: 'code_foo',
    client_secret: 'bar',
    redirect_uris: [`${ISSUER}/code_cb`],
    response_types: ['code'],
  }); // => Client
});

const app = express();

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

app.get('/code_cb', (req, res) => {
  const params = code_client.callbackParams(req);
  code_client.callback(`${ISSUER}/code_cb`, params, { code_verifier: codeVerifier }) // => Promise
  .then(function (tokenSet) {
    code_client.tokenSet = tokenSet;
    console.log(`Redirected to ${ISSUER}/code_userinfo`);
    res.redirect(`${ISSUER}/code_userinfo`);
  });
});

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

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

@lin826 these two examples (before and after) are identical in the way they work. The current one is just using a shorthand.

lin826 commented 5 years ago

In my case, without the specifying raised OPError: invalid_grant (grant request is invalid), while after one work great :)

panva commented 5 years ago

Maybe you were passing just { codeVerifier } as a shorthand, which is then obviously a different property. The code functions in both readme examples exactly the same.

Thanks for taking the time to open a PR tho, much appreciated <3