简体   繁体   中英

[node oidc provider]: Authorization code flow

I am trying to build an OAuth2.0 server using https://www.npmjs.com/package/oidc-provider .

The 2 main flows that I need to support are the client credentials one and the authorization code flow. For the latter the idea is to send an authorization code (OTP) to the user's email and exchange that for an access token.

Is the above achievable with this library? If not, are there any alternatives you could recommend, which are in working order and actively maintained?

Here is the request I am making to the /auth endpoint:

在此处输入图像描述

The above requests redirects me to the /interaction/:uid endpoint, where I am presented with the following details:

{"iat":1658821468,"exp":1658825068,"returnTo":"http://localhost:3000/oidc/auth/T6W8Cl7_bxYiiYC2AxG3f","prompt":{"name":"login","reasons":["no_session"],"details":{}},"params":{"client_id":"foo","code_challenge":"nELIDtDAvjgo5Hn0eh7mx4JmfFbfWZ166nwXwg89_zs","code_challenge_method":"S256","redirect_uri":"https://oauthdebugger.com/debug","response_mode":"query","response_type":"code"},"kind":"Interaction","jti":"T6W8Cl7_bxYiiYC2AxG3f"}

I may be wrong in how I understand the flow, but I expected to have a code field in the response / code parameter in the redirect url that I can then send to the user's email and (not exactly sure how) exchange it for the access token.

This is my current progress with the POC:

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

const PORT = 3000;
const app = express();

const oidcPrefix = '/oidc';

app.use(cors());

const oidc = new Provider('http://localhost:3000', {
  clients: [{
    client_id: 'foo',
    client_secret: 'bar',
    allowOmittingSingleRegisteredRedirectUri: true,
    redirect_uris: ['https://oauthdebugger.com/debug'],
    rotateRefreshToken: true,
    pkce: {
      required: true
    },
    grant_types: ['authorization_code', 'refresh_token'],
    response_types: ['code'],
    token_endpoint_auth_method: "client_secret_basic"
  }],
  interactions: {
    url: (_, interaction) => `${oidcPrefix}/interaction/${interaction.uid}`
  },
  features: {
    devInteractions: {
      enabled: false,
    },
    introspection: {
      enabled: true
    },
  },
  formats: {
    AccessToken: 'jwt',
  },
  jwks: {
    keys: [
      {
        d: 'VEZOsY07JTFzGTqv6cC2Y32vsfChind2I_TTuvV225_-0zrSej3XLRg8iE_u0-3GSgiGi4WImmTwmEgLo4Qp3uEcxCYbt4NMJC7fwT2i3dfRZjtZ4yJwFl0SIj8TgfQ8ptwZbFZUlcHGXZIr4nL8GXyQT0CK8wy4COfmymHrrUoyfZA154ql_OsoiupSUCRcKVvZj2JHL2KILsq_sh_l7g2dqAN8D7jYfJ58MkqlknBMa2-zi5I0-1JUOwztVNml_zGrp27UbEU60RqV3GHjoqwI6m01U7K0a8Q_SQAKYGqgepbAYOA-P4_TLl5KC4-WWBZu_rVfwgSENwWNEhw8oQ',
        dp: 'E1Y-SN4bQqX7kP-bNgZ_gEv-pixJ5F_EGocHKfS56jtzRqQdTurrk4jIVpI-ZITA88lWAHxjD-OaoJUh9Jupd_lwD5Si80PyVxOMI2xaGQiF0lbKJfD38Sh8frRpgelZVaK_gm834B6SLfxKdNsP04DsJqGKktODF_fZeaGFPH0',
        dq: 'F90JPxevQYOlAgEH0TUt1-3_hyxY6cfPRU2HQBaahyWrtCWpaOzenKZnvGFZdg-BuLVKjCchq3G_70OLE-XDP_ol0UTJmDTT-WyuJQdEMpt_WFF9yJGoeIu8yohfeLatU-67ukjghJ0s9CBzNE_LrGEV6Cup3FXywpSYZAV3iqc',
        e: 'AQAB',
        kty: 'RSA',
        n: 'xwQ72P9z9OYshiQ-ntDYaPnnfwG6u9JAdLMZ5o0dmjlcyrvwQRdoFIKPnO65Q8mh6F_LDSxjxa2Yzo_wdjhbPZLjfUJXgCzm54cClXzT5twzo7lzoAfaJlkTsoZc2HFWqmcri0BuzmTFLZx2Q7wYBm0pXHmQKF0V-C1O6NWfd4mfBhbM-I1tHYSpAMgarSm22WDMDx-WWI7TEzy2QhaBVaENW9BKaKkJklocAZCxk18WhR0fckIGiWiSM5FcU1PY2jfGsTmX505Ub7P5Dz75Ygqrutd5tFrcqyPAtPTFDk8X1InxkkUwpP3nFU5o50DGhwQolGYKPGtQ-ZtmbOfcWQ',
        p: '5wC6nY6Ev5FqcLPCqn9fC6R9KUuBej6NaAVOKW7GXiOJAq2WrileGKfMc9kIny20zW3uWkRLm-O-3Yzze1zFpxmqvsvCxZ5ERVZ6leiNXSu3tez71ZZwp0O9gys4knjrI-9w46l_vFuRtjL6XEeFfHEZFaNJpz-lcnb3w0okrbM',
        q: '3I1qeEDslZFB8iNfpKAdWtz_Wzm6-jayT_V6aIvhvMj5mnU-Xpj75zLPQSGa9wunMlOoZW9w1wDO1FVuDhwzeOJaTm-Ds0MezeC4U6nVGyyDHb4CUA3ml2tzt4yLrqGYMT7XbADSvuWYADHw79OFjEi4T3s3tJymhaBvy1ulv8M',
        qi: 'wSbXte9PcPtr788e713KHQ4waE26CzoXx-JNOgN0iqJMN6C4_XJEX-cSvCZDf4rh7xpXN6SGLVd5ibIyDJi7bbi5EQ5AXjazPbLBjRthcGXsIuZ3AtQyR0CEWNSdM7EyM5TRdyZQ9kftfz9nI03guW3iKKASETqX2vh0Z8XRjyU',
        use: 'sig',
      }, {
        crv: 'P-256',
        d: 'K9xfPv773dZR22TVUB80xouzdF7qCg5cWjPjkHyv7Ws',
        kty: 'EC',
        use: 'sig',
        x: 'FWZ9rSkLt6Dx9E3pxLybhdM6xgR5obGsj5_pqmnz5J4',
        y: '_n8G69C-A2Xl4xUW2lF0i8ZGZnk_KPYrhv4GbTGu5G4',
      },
    ],
  },
});

app.get(`${oidcPrefix}/interaction/:id`, async (req, res) => {
  const details = await oidc.interactionDetails(req, res);
  res.send(JSON.stringify(details))
});

app.get(`${oidcPrefix}/auth/:id`, async (req, res) => {
  const details = await oidc.interactionDetails(req, res);

  res.send(JSON.stringify(details))
});

app.use(oidcPrefix, oidc.callback());

app.listen(PORT, () => {
  console.log(`OAUTH Server listening on ${PORT}`);
})

I am open for any suggestions. Also, if you need me to provide additional details, do let me know. Thank you in advance!

Generally follow the section on User Flows in the documentation .

app.get('/interaction/:uid', async (req, res) => {
  //Send email with OTP
  //Display form to enter OTP. 
  //Form submission should POST to `/interaction/:uid/login`
});

app.post('/interaction/:uid/login', async (req, res) => {
  //verify OTP

  //if not valid, display error

  //if valid, call `interactionFinished`
  //this indicates to oidc-provider that the user has successfully authenticated
  return provider.interactionFinished(req, res, { login: { accountId: 'abc123' }});
);

That's about it

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM