GithubHelp home page GithubHelp logo

panva / node-openid-client Goto Github PK

View Code? Open in Web Editor NEW
1.7K 29.0 387.0 1.46 MB

OpenID Certified™ Relying Party (OpenID Connect/OAuth 2.0 Client) implementation for Node.js.

License: MIT License

JavaScript 97.93% TypeScript 2.07% Procfile 0.01%
oidc openid openid-client openid-connect passport connect client

node-openid-client's Introduction

Hi there 👋

I'm developing mostly Internet Standards covered software.

Late in 2015 I developed and until now continue to maintain and improve certified libraries to help developers consume OpenID Connect and OAuth 2 services. I strive to implement as many optional features as possible as well as implement early specification drafts to aid in interoperability testing and provide implementer's feedback back to IETF and OpenID Foundation as early and frequently as possible.

Support from the community to continue maintaining and improving these modules is welcome. If you find my modules useful, please consider supporting the projects by becoming a sponsor 💗.

node-openid-client's People

Contributors

barryhagan avatar bifurcation avatar big-kahuna-burger avatar blake-mealey avatar briangammon avatar caiquecastro avatar cplussharp avatar ctavan avatar danielsharvey avatar davidgtonge avatar dependabot[bot] avatar exidex avatar ffilipus avatar frederik avatar hitkodev avatar jaulz avatar jonalu avatar kg0r0 avatar kgraney avatar madarche avatar mthadley avatar oladon avatar panva avatar pnappa avatar prust avatar roemba avatar sawyerh avatar svvac avatar tayloa45 avatar thecodeite avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

node-openid-client's Issues

Incompatible assert OpenIDConnectStrategy when using koa-passport

I current Switch my App from Express and found a Problem with the OpenIDConnectStrategy when using koa-passport

I think the following message pops up since koa-passport mocks the RequestObject into a Object and so its can never be a IncomingMessage or a String
AssertionError [ERR_ASSERTION]: #callbackParams only accepts string urls or http.IncomingMessage

I hope That can be fixed or i need a alternative for koa-passport or passport in general.

Localhost request errors (RequestError: connect ECONNREFUSED 127.0.0.1:3000)

Hi, thank you for this package! I'm hoping you might be able to provide guidance on an error I'm seeing when I use it to authenticate against a locally-running identity provider (rails app running on localhost:3000).

I notice when I start my node app, this package attempts to make various authentication requests to 127.0.0.1:3000 URLs, but these requests aren't able to find the identity provider server. The requests produce RequestError: connect ECONNREFUSED 127.0.0.1:3000 errors (logs below):

--->> DEBUG=my-identity-sp:* npm start

> [email protected] start /Users/username/projects/my-identity-sp
> nodemon ./bin/www

[nodemon] 1.14.1
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node ./bin/www`
CONFIGURATION ERROR { RequestError: connect ECONNREFUSED 127.0.0.1:3000
    at ClientRequest.req.once.err (/Users/username/projects/my-identity-sp/node_modules/openid-client/node_modules/got/index.js:219:22)
    at Object.onceWrapper (events.js:315:30)
    at emitOne (events.js:121:20)
    at ClientRequest.emit (events.js:211:7)
    at Socket.socketErrorListener (_http_client.js:387:9)
    at emitOne (events.js:116:13)
    at Socket.emit (events.js:211:7)
    at emitErrorNT (internal/streams/destroy.js:64:8)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)
  name: 'RequestError',
  code: 'ECONNREFUSED',
  host: 'localhost:3000',
  hostname: 'localhost',
  method: 'GET',
  path: '/.well-known/openid-configuration',
  protocol: 'http:',
  url: 'http://localhost:3000/.well-known/openid-configuration' }

It makes sense that requests to 127.0.0.1:3000 produce errors, but I'm wondering why requests are being made to 127.0.0.1:3000 instead of localhost:3000.

When I visit http://localhost:3000/.well-known/openid-configuration in a browser, I get the expected response. Here is an abbreviated snippet from the identity provider's well-known config file:

{
        ...
	"authorization_endpoint": "http://localhost:3000/openid_connect/authorize",
	"issuer": "http://localhost:3000/",
	"jwks_uri": "http://localhost:3000/api/openid_connect/certs",
	"token_endpoint": "http://localhost:3000/api/openid_connect/token",
	"userinfo_endpoint": "http://localhost:3000/api/openid_connect/userinfo",
	"end_session_endpoint": "http://localhost:3000/openid_connect/logout",
	...
}

Note: when I try manual discovery using hard-coded well-known config values, configuration works, but subsequent requests produce the same client error.

I've found a temporary work-around for this issue, running the identity provider using the following command: rails s -b 0.0.0.0, but it ends up producing other issues pertaining to how the identity provider runs, so I was hoping to learn more about the client request errors and how I might fix them.

Do you have any ideas on where the disconnect is? Thank you for your time.

state mismatch

Hello,

When I tried to do authorization code flow, I always have an this error:

Error: state mismatch
    at Client.authorizationCallback (/var/www/html/node_modules/openid-client/lib/client.js:309:29)
    at OpenIDConnectStrategy.authenticate (/var/www/html/node_modules/openid-client/lib/passport_strategy.js:137:27)
    at attempt (/var/www/html/node_modules/passport/lib/middleware/authenticate.js:361:16)
    at authenticate (/var/www/html/node_modules/passport/lib/middleware/authenticate.js:362:7)
    at Layer.handle [as handle_request] (/var/www/html/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/var/www/html/node_modules/express/lib/router/index.js:317:13)
    at /var/www/html/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/var/www/html/node_modules/express/lib/router/index.js:335:12)
    at next (/var/www/html/node_modules/express/lib/router/index.js:275:10)
    at Layer.handle [as handle_request] (/var/www/html/node_modules/express/lib/router/layer.js:91:12)
    at trim_prefix (/var/www/html/node_modules/express/lib/router/index.js:317:13)
    at /var/www/html/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/var/www/html/node_modules/express/lib/router/index.js:335:12)
    at next (/var/www/html/node_modules/express/lib/router/index.js:275:10)
    at SessionStrategy.strategy.pass (/var/www/html/node_modules/passport/lib/middleware/authenticate.js:338:9)
    at SessionStrategy.authenticate (/var/www/html/node_modules/passport/lib/strategies/session.js:75:10)
    at attempt (/var/www/html/node_modules/passport/lib/middleware/authenticate.js:361:16)
    at authenticate (/var/www/html/node_modules/passport/lib/middleware/authenticate.js:362:7)
    at Layer.handle [as handle_request] (/var/www/html/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/var/www/html/node_modules/express/lib/router/index.js:317:13)
    at /var/www/html/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/var/www/html/node_modules/express/lib/router/index.js:335:12)

And when I debug my node-oidc-provider, it seems my state is changing like this

user-service_1   | user-servi | [2017-12-19T15:29:32.333] [INFO] default - ==== USER SERVICE ====
user-service_1   | user-servi | [2017-12-19T15:29:32.336] [INFO] default - BEGINNING USER SERVICE
user-service_1   | user-servi | [2017-12-19T15:29:32.344] [INFO] default - REGISTERING REDIS TO DI
user-service_1   | user-servi | [2017-12-19T15:29:32.345] [INFO] default - REGISTRATION DONE.
user-service_1   | user-servi | [2017-12-19T15:29:32.489] [INFO] default - REGISTERING SERVICES TO DI
user-service_1   | user-servi | NOTICE: a draft/experimental feature (sessionManagement) enabled, future updates to this feature will be released as MINOR releases
user-service_1   | user-servi | [2017-12-19T15:29:32.517] [INFO] default - REGISTRATION DONE.
user-service_1   | user-servi | [2017-12-19T15:29:32.517] [INFO] default - STARTING SERVER...
user-service_1   | user-servi | [2017-12-19T15:29:32.669] [INFO] default - SERVER STARTED AT PORT: 3000
user-service_1   | user-servi | 2017-12-19T15:30:06.470Z oidc-provider:authentication:accepted uuid=144baad5-2a9b-4977-b21c-f0ad050ff7ad Params { acr_values: undefined, claims: undefined, claims_locales: undefined, client_id: 'zELcpfANLqY7Oqas', code_challenge: undefined, code_challenge_method: undefined, display: undefined, id_token_hint: undefined, login_hint: undefined, max_age: undefined, nonce: undefined, prompt: undefined, redirect_uri: 'https://docker.for.mac.localhost/auth/cb', registration: undefined, request: undefined, request_uri: undefined, response_mode: 'query', response_type: 'code', scope: 'openid email', state: '7f31cd25-377f-4cc1-8f41-e9578052702f', ui_locales: undefined }
user-service_1   | user-servi | 2017-12-19T15:30:06.475Z oidc-provider:authentication:interrupted uuid=144baad5-2a9b-4977-b21c-f0ad050ff7ad interaction={ error: 'login_required', error_description: 'End-User authentication is required', reason: 'no_session', reason_description: 'Please Sign-in to continue.' }
user-service_1   | user-servi | [2017-12-19T15:30:06.501] [INFO] default - see what else is available to you for interaction views Session {
user-service_1   | user-servi |   returnTo: 'https://docker.for.mac.localhost:81/oidc/auth/144baad5-2a9b-4977-b21c-f0ad050ff7ad',
user-service_1   | user-servi |   interaction: 
user-service_1   | user-servi |    { error: 'login_required',
user-service_1   | user-servi |      error_description: 'End-User authentication is required',
user-service_1   | user-servi |      reason: 'no_session',
user-service_1   | user-servi |      reason_description: 'Please Sign-in to continue.' },
user-service_1   | user-servi |   uuid: '144baad5-2a9b-4977-b21c-f0ad050ff7ad',
user-service_1   | user-servi |   params: 
user-service_1   | user-servi |    { client_id: 'zELcpfANLqY7Oqas',
user-service_1   | user-servi |      redirect_uri: 'https://docker.for.mac.localhost/auth/cb',
user-service_1   | user-servi |      response_mode: 'query',
user-service_1   | user-servi |      response_type: 'code',
user-service_1   | user-servi |      scope: 'openid email',
user-service_1   | user-servi |      state: '7f31cd25-377f-4cc1-8f41-e9578052702f' },
user-service_1   | user-servi |   id: '144baad5-2a9b-4977-b21c-f0ad050ff7ad' }
user-service_1   | user-servi | 2017-12-19T15:30:24.084Z oidc-provider:authentication:resumed uuid=144baad5-2a9b-4977-b21c-f0ad050ff7ad { login: { account: '5a37ed54852e8d0044de7336', acr: '1', remember: true, ts: 1513697424 }, consent: { scope: 'openid email' } }
user-service_1   | user-servi | NOTICE: default helper interactionCheck called, you should probably change it in order to to define the policy for requiring End-User interactions.
user-service_1   | user-servi | 2017-12-19T15:30:24.092Z oidc-provider:authentication:success uuid=144baad5-2a9b-4977-b21c-f0ad050ff7ad { code: 'OWNiMjEwOGYtNmZjMy00ZGQzLTkxNzgtODBmYTAyYTEzN2Y5_8g2B8_NsKHh5mBRdKge6xYGJfvDCS70KFI97jI1TBLJ7Sk0gWvVXOFpCFux_4I2v9DlFePu8DtCv_XplvVnkA', state: '7f31cd25-377f-4cc1-8f41-e9578052702f', session_state: '349c1feee28805f640427f0bfeabf073e3102518ecdf8bef1664977ccbd6c8e7.6f931315a4e555e7' }

I don't know what is the issue here, what is being compared. I am using self signed certificate for development, and also two services in my system, one is api-gateway as gateway and proxy and other one is user-service as my authorization service. I activate express session in my api-gateway with cookie secure to true in my api-gateway
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: true, cookie: { secure: true }, }));

Any other problem with my setting that cause error?

post logout redirect session endpoint

I'm using this client with https://github.com/panva/node-oidc-provider.

After some success implementing oidc flows for authentication I turned off the experimental sessionManagment feature because it started throwing an error.

In the get.logout route on the client I changed the following to work around the error.

      ctx.redirect(url.format(Object.assign(url.parse(issuer.end_session_endpoint), {
        search: null,
        query: {
          id_token_hint: tokens.id_token,
          post_logout_redirect_uri: url.resolve(ctx.href, '/'),
        },
      }))); 

to

   if (issuer.end_session_endpoint) {
      ctx.redirect(url.format(Object.assign(url.parse(issuer.end_session_endpoint), {
        search: null,
        query: {
          id_token_hint: tokens.id_token,
          post_logout_redirect_uri: url.resolve(ctx.href, '/'),
        },
      })));
    } else ctx.redirect('/');

I'll be delighted when I understand the session management feature well enough to stop getting the error. the last time I saw it it was because I'd inadvertently introduced a mismatch in urls between the OP and RP. Currently it's more expedient to simply turn off the feature and leave session management alone for the moment.

Maybe it's trivial, but I was looking for any way to say thank you for making the oidc provider and client available. I thought you might consider this edit as helps the 'default' behaviour of the client.

  • thank you, it's a wonderful package!

Unable to get Authorization_Code flow working

Hi,

Hope all is well. I've been struggling for almost a whole day to get the authorization code flow implemented.

I am also using the oidc-provider as a backend. What I have that is custom is a custom adapter (that implements sequelize) and a custom account. (Not sure if this is where the problem is)

The only error I get is: POST /idp/token 500 41.618 ms - 72

Please help! :(

Confused about usage with passport.js

Hi there,

Thanks for providing this repo, I'm learning a lot studying it. I hope this question is not too vague, so I've been trying to figure out how to ask this best.

As suggested I've set up an working example of your OP and RP examples to experiment with. ([email protected] gets authenticated and authorized, everything works smoothly, but now I would like my own user manager)

I'm confused about usage with passport.js and node-openid-provider.

The login/authentication page is located on the node-oidc-provider. The node-openid-client instance on the RP redirects the UserAgent to the issuers /auth url (with a callback) when a protected resource needs auth intercations...

The notes say pass the client instance to the passport Strategy once you have it.

How do I "pass the client to the passport strategy"?

Where is passport.js required? In the RP app.js?

From the example "Usage With Passport" I try addin this require.

const Strategy = require('openid-client').Strategy;

It warns about recursive includes (as it should given it would create a circular reference!)...

So how and where do I require the openid-client passport Strategy? In the OP authentication page?

So I never get this far:

// start authentication request
app.get('/auth', passport.authenticate('oidc'));

Is there supposed to be a login view provided on the RP for each OP's passport strategy? Would they be express apps like the oidc-provider-example auth page is?

A pointer would be much appreciated.

Thanks

Angular2 Hybrid Flow

Hi @panva,

I am creating an angular 2 app with hybrid flow authentication,it would be great if you can suggest some ways in which this library can be used to achieve this. Some examples could also be handy. Thanks :-)

Verify User Question

So, I do not want to verify my user information and would like to not have to include a user information endpoint in that scenario, is that possible?

I was looking through the source but it looks like it is always required right now.

This is using passport too btw. If I don't do the passport way I can do this.

state mismatch

hi,
I run into a state mismatch error, i read the previous issue but i dont understant what to do.
im using express with passport

state mismatch

Error: state mismatch
    at Client.authorizationCallback (C:\appl\tmi\node_modules\openid-client\lib\client.js:309:29)
    at OpenIDConnectStrategy.authenticate (C:\appl\tmi\node_modules\openid-client\lib\passport_strategy.js:137:27)
    at attempt (C:\appl\tmi\node_modules\passport\lib\middleware\authenticate.js:361:16)
    at authenticate (C:\appl\tmi\node_modules\passport\lib\middleware\authenticate.js:362:7)
    at Layer.handle [as handle_request] (C:\appl\tmi\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\appl\tmi\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\appl\tmi\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\appl\tmi\node_modules\express\lib\router\layer.js:95:5)
    at C:\appl\tmi\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\appl\tmi\node_modules\express\lib\router\index.js:335:12)

i checked the cookie and its not secure:

app.use(session({ secret: 'foo', resave: false, saveUnitialized: true, cookie: { secure: false } }));

and the callback return 2 params: code and state.

i need help, please 😄

Verify callback never being called

Hello there,
I am trying to use the passport strategy, I get redirected to my Auth server and redirect back to my redirect_url but the verify callback never gets called. What am I missing?

const Issuer = require('openid-client').Issuer;
const Strategy = require('openid-client').Strategy;

Issuer.discover('http://localhost:5000')
    .then(idSrvIssuer => {
        const client = new idSrvIssuer.Client({
            client_id: 'my_client',
            client_secret: ''
        });

        const params = {
            redirect_uri: 'http://localhost:5004/callback',
            response_type: 'id_token',
            response_mode: 'form_post',
            scope: 'openid profile',
            claims: {
                id_token: { email_verified: null },
                userinfo: { sub: null, email: null },
            },
        }
        passport.use('oidc', new Strategy({ client, params }, (tokenset, userinfo, done) => {
           // **NEVER GET HERE**
            console.log('tokenset', tokenset);
            console.log('access_token', tokenset.access_token);
            console.log('id_token', tokenset.id_token);
            console.log('claims', tokenset.claims);
            console.log('userinfo', userinfo);
        }));
        app.use(passport.initialize());
        app.use(passport.session()); // persistent login sessions
    })
    .catch(ex => {
        console.log(ex)
    })
app.get('/', passport.authenticate('oidc'), function (req, res) {
    res.send('hello!!');
});

app.post('/callback', function (req, res) {
    console.log('In callback', req.user)
    res.send(200);
})

I get to /callback but I do not have any of the claims or user info.

Let developer specify a "skew time" on iat

My server clocks are out of sync by a few milliseconds, and the iat check fails with AssertionError: id_token issued in the future.

I would like to configure a time skew so that I can add x milliseconds to the timestamp, so that my servers doesn't have to bee 100% in sync for the system to work.

How to retrieve the JSON Web Key Set?

Apologies if I'm being dumb or missing something :-) , but I'm not able to figure out what API/syntax to use to retrieve the JWKS.

I'm able to do it manually by sending a GET request to the JWKS URL for the OpenID server I'm using (with a valid code attached to the query string), but can't work out from the documentation and examples how I do the equivalent using openid-client

A quick pointer / simple example would be a great help. Many thanks!

Discovered token_endpoint_auth_methods_supported not used by client

It seems the Client never uses the discovered token_endpoint_auth_methods_supported from the Issuer but instead always defaults to using client_secret_basic.

I know that this can be overwritten by setting token_endpoint_auth_method on the Client but it's confusing that it's unable to select a supported method by itself, considering that the Issuer has the information. It also appears to break with the intended behaviour described in the spec:

token_endpoint_auth_methods_supported
OPTIONAL. JSON array containing a list of Client Authentication methods supported by this Token Endpoint. The options are client_secret_post, client_secret_basic, client_secret_jwt, and private_key_jwt, as described in Section 9 of OpenID Connect Core 1.0 [OpenID.Core]. Other authentication methods MAY be defined by extensions. If omitted, the default is client_secret_basic -- the HTTP Basic Authentication Scheme specified in Section 2.3.1 of OAuth 2.0 [RFC6749].

http://openid.net/specs/openid-connect-discovery-1_0.html

Here's the discovered metadata for my Issuer and Client

Issuer metadata

{
  claims_parameter_supported: false,
  grant_types_supported: ['authorization_code', 'implicit'],
  request_parameter_supported: false,
  request_uri_parameter_supported: true,
  require_request_uri_registration: false,
  response_modes_supported: ['query', 'fragment'],

  token_endpoint_auth_methods_supported: ['client_secret_post'],

  issuer: 'https://api.some-host.com',
  authorization_endpoint: 'https://api.some-host.com/oauth/authorize',
  token_endpoint: 'https://api.some-host.com/oauth/token',
  token_endpoint_auth_signing_alg_values_supported: ['RS256'],
  userinfo_endpoint: 'https://api.some-host.com/oauth/userinfo',
  jwks_uri: 'https://api.some-host.com/oauth/jwks.json',
  response_types_supported: ['code'],
  introspection_endpoint: undefined,
  introspection_endpoint_auth_methods_supported: ['client_secret_post'],
  introspection_endpoint_auth_signing_alg_values_supported: ['RS256'],
  revocation_endpoint: undefined,
  revocation_endpoint_auth_methods_supported: ['client_secret_post'],
  revocation_endpoint_auth_signing_alg_values_supported: ['RS256'],
}

Client metadata

{
  application_type: 'web',
  grant_types: ['authorization_code'],
  id_token_signed_response_alg: 'RS256',
  response_types: ['code'],

  token_endpoint_auth_method: 'client_secret_basic',

  client_id: '6462923d-8061-46ab-8136-103a1a2a36e8',
  client_secret: 'f624a3fd-d5aa-4300-bc60-6f2a3eced8e1',
  introspection_endpoint_auth_method: 'client_secret_basic',
  introspection_endpoint_auth_signing_alg: undefined,
  revocation_endpoint_auth_method: 'client_secret_basic',
  revocation_endpoint_auth_signing_alg: undefined,
}

Problem dealing with URLs that have a trailing slash

I am trying to connect with oauth openID connect to a WordPress installation. WordPress is very strict about ensuring every page has exactly one URL. Because of this, it redirects a URL without a trailing slash to one with a trailing slash. (Or vice versa, but that depends on the settings)

So when trying to connect I get the error: "expected 200 OK with body, got 301 Moved Permanently without one". This is because the library does a request to .well-known/openid-configuration without a trailing slash by default.

I think there are two solution for this:

  1. Following 301 redirects
  2. Allowing the user of the library to set whether to include a trailing slash when requesting endpoints.

README Minor Issue

The README part about using this with passport has a section about params and describes the default value of redirect_uri but it doesn't show it being a part of the client.

Another words
// redirect_uri defaults to redirect_uris[0]
should be
// redirect_uri defaults to client.redirect_uris[0]

Undefined value returned from authorizationCallback breaking passport

Following on from #49, I still can't get passport up and running. The current issue is that authorizationCallback returns an undefined value.

The query parameters for the callback endpoint are shown as:

state:XXX
code:XXX
authuser:0
session_state:61c305bab9bcb8d691b7996fdbe40120becb5656..2bd3
prompt:none

My read of the code is that because id_token is not set, this method won't ever return a defined value.

I really didn't want to have to read the standard, but it does seem that callbacks that only set code are possible, as seems to be happening.

However, the code backtrace is coming from a regular router.use(passport.authenticate('oidc')); that I attach to my endpoints, and I have no idea how these values make their way into a regular protected passport endpoint. I'm assuming I have to do something like passport.authenticate('oidc') as a middleware on my endpoints, but I am guessing here to some extent.

Is this how I am supposed to protect an endpoint when using with passport?

Any suggestions on how to move this forward?

TypeError: Cannot read property 'then' of undefined
    at OpenIDConnectStrategy.authenticate (/mnt/data/git/turalt-demo/node_modules/openid-client/lib/passport_strategy.js:94:7)
    at attempt (/mnt/data/git/turalt-demo/node_modules/passport/lib/middleware/authenticate.js:361:16)
    at authenticate (/mnt/data/git/turalt-demo/node_modules/passport/lib/middleware/authenticate.js:362:7)
    at Layer.handle [as handle_request] (/mnt/data/git/turalt-demo/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:317:13)
    at /mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:335:12)
    at next (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:275:10)
    at Function.handle (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:174:3)
    at router (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:47:12)
    at Layer.handle [as handle_request] (/mnt/data/git/turalt-demo/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:317:13)
    at /mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:335:12)
    at next (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:275:10)
    at SessionStrategy.strategy.pass (/mnt/data/git/turalt-demo/node_modules/passport/lib/middleware/authenticate.js:338:9)

Provider session logout with Passport Strategy

Hello again!

Thanks for these two great (certified) libraries. They are super helpful.

I see how (in the example) you could handle a /logout scenario, where you revoke any potentially active access_token and use the issuer.end_session_endpoint to perform a browser redirect to the Provider's session management logout endpoint, but I have a general question about implementing this while using the Passport Strategy:

With Passport, you would normally use something like this:

app.get('/logout', (req, res) => {
  req.logout() // end passport session
  res.redirect('/')
})

So I want to do something like this:

app.get('/logout', (req, res) => {
  req.logout() // end passport session
  
  const url = `${req.protocol}://${req.get('host')}${req.baseUrl}`
  res.redirect(`${exampleIssuer.end_session_endpoint}?post_logout_redirect_uri=${encodeURIComponent(url)}`)
})

How can I retrieve the id_token_hint or revoke any remaining access_token – are they accessible somewhere or would it be helpful to extend the Passport Strategy itself to encapsulate these things in some form of passport.logout()?

Storage of discovered public keys etc. in a database

I was wondering if it was possible to be able to perform the issuer discovery and then have the details that come back stored in a database. I cant see any kind of documentation or config that would allow this.

If possible it would allow a convenient means of using this package in an AWS Lambda without having to make an external call out to the secure token service for each new request. A timeout feature like forcing a new discovery every 5 minutes or so would be excellent.

Thanks a lot.

Nonce defaulted to undefined when using refresh

I might have misunderstood something, but why does the id token validation default to 'undefined' for nonce when validating the id token of a refresh token call?

I've looked through the open id specs and even though they don't explicitly talk about the nonce field in the section on refresh tokens, they do however state that "otherwise, the same rules apply as apply when issuing an ID Token at the time of the original authentication".

I'm using the Mitre Open ID connect server and if I try to refresh, the tokens I get back have the nonce field set to the same value as the original id token I used for my first authentication.

As I see it the nonce value for id token validation should be set to undefined only if the original token did not use nonce.

Thoughts on that?

Question: How do I set up proxy settings?

I tried to add my settings to the defaultHttpOptions property like so:

Issuer.defaultHttpOptions = {
			host: 'proxy',
			port: 8888,
			path: 'https://myoidcserver.com',
			headers: {
				Host: "myoidcserver.com"
			}
		};
Issuer.discover(config.idSrv.url)
			.then(.....

But that doesn't seem to work. The only reason I added the path is because of this SO answer. Even with just the host and the port it does not work and the connection times out. What am I missing?

more logging / debug options

Hey @panva,

Thanks for making a great library. This makes doing OIDC in Node really easy.

I was wondering, would you consider accepting a PR to add some logging? The API I was considering was this:

/*
interface ILogger {
  log(message: string)
  warn(message: string)
  info(message: string)
  error(message: string)
}
*/

const issuer = new Issuer({
   logger: console,  /* implements ILogger */
});

// Would inherit logger from issuer, but could also pass logger into the client
const client = new issuer.Client({ 
   logger:  console,  /* implements ILogger */
});

My use case is a container cluster which I monitor via CloudWatch. It's not easy to tell what errors we're getting from got, particularly when proxies or redirects are involved. If you're happy with the API, I can write the code/tests.

error issuer must be configured with introspection endpoint

When using this library with Auth0, either automatically with Issuer.discover() or manually with new Issuer(), the following error is thrown:

issuer must be configured with introspection endpoint

Since both this library and Auth0 are certified, I am not sure which one is at fault so I am opening an issue on both.

This library requires an introspect_endpoint which Auth0 doesn't provide. From my understanding, it seems that this is an OAuth2 specific concept that is not required by OpenID.

dynamic userAgent in all requests

I've noticed that in all requests that the client makes, the useragent is always static. Should it better be dynamic based on the user-agent of the request? The real users user-agent?

It is possible to change it using Issuer.defaultHttpOptions and maybe change that setting every time before a request is made using the client but its not that elegant in my opinion because its should be a default that is set 1 time.
I didnt see that the code allows you to pass a dynamic header / user-agent through the flow.

Editing Issuer iss values

I'm using this excellent library to connect to https://login.microsoftonline.com/common/oauth2/authorize

Unfortunately, Microsoft uses a somewhat proprietary take on their .well-known/openid-configuration template.

{
  "issuer": "https://sts.windows.net/{tenantid}/" // the issue
  ...
}

They are specifying a template where they expect the client to replace the tag {tenantId} with an arbitrary value. I am not looking for template support in node-openid-client.

I'm trying to find a way to hack / set the iss value of an Issuer() instance. However, it seems that the value cannot be changed without refactoring the code. Is this correct, or have I overlooked a possibility?

No exposed method to get the user identity from the token

I've looked in the code and I do not see any way to extract the identity from the id_token without doing it myself. It seems easy enough (base64Decode(id_token.split(',')[1])), but I really think this should be a method of the Client class.

RequestError: Request timed out in authorizationCallback

Hello Panava,
I'm trying to use openid-client in es5.
after I create my url I want to use authorizationCallback promise but it goes in catch and I get timed out error.

var clientQuery = client.callbackParams(query);
client.authorizationCallback('http://example.com/cb', clientQuery, {state: state})
        .then(function (tokenSet) {
            console.log('received and validated tokens %j', tokenSet);
            console.log('validated id_token claims %j', tokenSet.claims);
        })
        .catch(function (e) {
            logger.writeLog(e);
        });

Unnecessary `new` for `googleIssuer.Client.fromUri` in README.md

The sample code in the documentation:

new googleIssuer.Client.fromUri(registration_client_uri, registration_access_token) // => Promise
  .then(function (client) {
    console.log('Discovered client %s', client);
  });

will produce:

TypeError: googleIssuer.Client.fromUri is not a constructor

I removed new then I could get the client as expected.

googleIssuer.Client.fromUri(registration_client_uri, registration_access_token) // => Promise
  .then(function (client) {
    console.log('Discovered client %s', client);
  });

timeouts with 1.11.1

When we moved to 1.11.1 we started experiencing timeouts with our openid client.

We have two customizations. One sets the clock tolerance, the other is setting the default timeout to 20 seconds. Is how we are setting the timeout incorrect with the new version? It worked with the old version.

Issuer.defaultHttpOptions = {timeout: 20000};
client.CLOCK_TOLERANCE = 5;

help needed: using open-id-client with passport

When I run my express app, I get this error:
TypeError: Cannot read property 'callbackParams' of undefined at OpenIDConnectStrategy.authenticate (../grant/node_modules/openid-client/lib/passport_strategy.js:63:31) at attempt (../grant/node_modules/passport/lib/middleware/authenticate.js:348:16)
I'm including code snippet from my app.js file:

exports.appPromise = new Promise(resolve => {
  Issuer.discover('xxxxxxx')
    .then(function (identityIssuer) {
      app.use(bodyParser.json());
      app.use(bodyParser.urlencoded({
        extended: false
      }));
      app.use(cookieParser());
      app.use(express.static(path.join(__dirname, 'public')));
      app.use(cookieSession({
        secret: 'xxxx',
        resave: false,
        saveUninitialized: true,
        cookie: {
          secure: true
        }
      }));
      let client = new identityIssuer.Client({
        client_id: 'emailAPI',
        client_secret: 'xx'
      });
      passport.use('oidc', new Strategy(client, (tokenset, userinfo, done) => {
        console.log('tokenset', tokenset);
        console.log('access_token', tokenset.access_token);
        console.log('id_token', tokenset.id_token);
        console.log('claims', tokenset.claims);
        console.log('userinfo', userinfo);
        return done(null, false);
      }));
      app.use(passport.initialize());
      app.use('/users', passport.authenticate('oidc'), function (req, res) {
        console.log('httpOptions %j', Issuer.defaultHttpOptions);
        res.send(client.authorizationUrl({
          redirect_uri: 'xxx',
          scope: 'openid email'
        }));
      });
      resolve(app);
    });
});

PKCE Support

Hi,

Thanks for both this and the node-oidc-provider project!

I'd like to add in support for PKCE.
While this is mainly for public clients, there are use-cases to support it for confidential clients.
I'm thinking of adding a 4th optional argument to this method:

authorizationCallback(redirectUri, parameters, checks) { ... }
// to:
authorizationCallback(redirectUri, parameters, checks, codeVerifier) { ... }

No change is needed for the client.authorizationUrl method.

What do you think?

v1.7.0 fails in npm install

Install of latest client fails with following error.

> npm i openid-client
npm ERR! cb() never called!

Previous version is fine.

Append client_id to session key in passport strategy

Hi, I'm hoping to use your library as-is without a fork, but I would like to append client_id to the session key in Passport Strategy. Something like this:
const sessionKey = `oidc:${url.parse(issuer.issuer).hostname}:${client.client_id}`;

Our node backend is shared by multiple apps at the moment. Even though they could all work with the same client_id, we want separate client_ids for each set up in the OP. I can create an instance of the strategy for each client, but presently they would all share the same session key since the issuer settings are the same. It's an edge case scenario, but adding client_id will ensure that it's picking up the right one if the user had 2 tabs going and somehow attempted to login at nearly the same time.

Would you consider a PR with this small change? If the whole thing is a bad idea, let me know that too :)

getting ESOCKETTIMEDOUT error very frequently

We are using node-openid-client for Azure B2C scenarios and able to get the tokenset using manual configuration.

But maximum times when we requesting for access-token, refresh-token by sending authorization-code grant type this library returning below error.

{"code":"ESOCKETTIMEDOUT","message":"Socket timed out on request to login.microsoftonline.com","host":"login.microsoftonline.com","hostname":"login.microsoftonline.com","method":"POST","path":"/tfp/tenantazureb2c.onmicrosoft.com/b2c_1_sign_in/oauth2/v2.0/token"}

How to get ride of this error?

AssertionError: expected 200 OK with body, got 200 OK without one

I'm receiving this error with my token response. Is this a failure on Twitch's part to respond with the status code inside the body? Any ideas on how I should proceed?

Response { 
  statusCode: 200,
  headers:
   {
     'content-type': 'application/json; charset=utf-8',
     server: 'nginx',
     'access-control-allow-origin': '*',
     'cache-control': 'no-cache, no-store, must-revalidate, private',
     expires: '0',
     pragma: 'no-cache',
     'twitch-trace-id': '...',
     'x-ctxlog-logid': '...',
     'front-end-https': 'on',
     'timing-allow-origin': 'https://www.twitch.tv',
     vary: 'Accept-Encoding',
     date: 'Thu, 14 Sep 2017 19:14:58 GMT',
     'content-length': '209',
     connection: 'close' },
  trailers: {},
  httpVersion: '1.1',
  url: 'https://api.twitch.tv/api/oauth2/token',
  method: null,
  body: '{
    "refresh_token":"...",
    "access_token":"...",
    "scope":"channel_check_subscription chat_login user_follows_edit user_read",
    "expires_in":0
  }'
}
{ AssertionError: expected 200 OK with body, got 200 OK without one
    at expectResponseBody (/Users/ovenbird/Documents/Projects/AStreamForVoices/astreamforvoices/node_modules/openid-client/lib/expect_response.js:8:5)

    at process._tickCallback (internal/process/next_tick.js:103:7)
  name: 'AssertionError',
  actual: '',
  expected: true,
  operator: '==',
  message: 'expected 200 OK with body, got 200 OK without one',
  generatedMessage: false }

on app.js

Hey ,

I´m getting an issue on running the client. What am i missing?

/node/node-openid-client/example/app.js:25
app.use(async (ctx, next) => {
^
SyntaxError: Unexpected token (
at createScript (vm.js:56:10)

Hoping to get some help.. tks

Invalid token issuer

Hi,

I have a tricky issue and I need your help to solve it.

I'm implementing OpenID Connect on my own infrastructure. I have set up an Openshift platform and installed my services on it.

I have a Keycloak (an OpenId Connect server) installation and my app that connects to it.

The keycloak is available externally at identity.myapp.com
My app is available externally at app.myapp.com

Openshift doesn't let my app talk to Keycloak using the external route, as they are in the same network and can't access the Openshift Integrated proxy from the inside.

Therefore my OpenId Issuer setup is :

const keycloak = new Issuer({
                    issuer: "https://identity.myapp.com/auth/realms/master",
                    authorization_endpoint: "https://identity.myapp.com/auth/realms/master/protocol/openid-connect/auth",
                    token_endpoint: http://keycloak-openshift:8080/auth/realms/master/protocol/openid-connect/token",
                    userinfo_endpoint: "http://keycloak-openshift:8080/auth/realms/master/protocol/openid-connect/userinfo",
                    jwks_uri: "http://keycloak-openshift:8080/auth/realms/master/protocol/openid-connect/certs"
                });

Note that the issuer and authorization endpoint point to the external route, and all the other endpoints used by the app point to the internal route.

When I try to retrieve the token I get this error :

{ OpenIdConnectError: invalid_token
    at Client.gotErrorHandler (/opt/app-root/src/node_modules/openid-client/lib/error_handler.js:8:11)
    at process._tickCallback (internal/process/next_tick.js:103:7)
  message: 'invalid_token',
  error: 'invalid_token',
  error_description: 'Token invalid: Invalid token issuer. Expected \'http://keycloak-openshift-3:8080/auth/realms/master\', but was \'https://identity.myapp.com/auth/realms/master\'',
  state: undefined,
  scope: undefined }

As you can see, the library expects the issuer value in the token to be set at the internal route, but Keycloak sets it to the external route (as it is called from outside).

Is there a way to tell the library to check the issuer with the value passed at the Issuer instantiation ? Or is there a way to disable the issuer validation (i'm in a private Docker network)

For sure I cannot use the external route from my app. My only other solution would be to take Keycloak out of my platform but I lose the easy scalability and reliability benefits.

expose got's option useElectronNet

Because got is setting useElectronNet to true by default without having it in its dependencies. Would it be possible to expose this option so we can choose to set it to false if need be ?

Ideally I'd set it to false by default and let the user change it if he uses electron.

Cheers

Strategy callback never called

I have this code

const express = require('express');
const app = express();
const passport = require('passport');
const Strategy = require('openid-client').Strategy;
const Issuer = require('openid-client').Issuer;
var cookieSession = require('cookie-session');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');

const issuer = new Issuer({
  issuer: 'http://localhost:5000',
  authorization_endpoint: 'http://localhost:5000/connect/authorize',
  token_endpoint: 'http://localhost:5000/connect/token',
  userinfo_endpoint: 'http://localhost:5000/connect/userinfo',
  jwks_uri: 'http://localhost:5000/.well-known/openid-configuration/jwks'
});

const client = new issuer.Client({
  client_id: 'xxx',
  client_secret: 'xxx'
});

const params = {
  "redirect_uri": "http://localhost:3000/users",
  "response_type": "code id_token token",
  "scope": "xxx openid profile",
  "authentication_type": "xxx"
};

passport.use('oidc', new Strategy({ client, params }, function (tokenset, userinfo, done) {
  console.log('tokenset', tokenset);
  console.log('access_token', tokenset.access_token);
  console.log('id_token', tokenset.id_token);
  console.log('claims', tokenset.claims);
  console.log('userinfo', userinfo);

  return done(null, false);
}));

app.use(cookieParser());
app.use(bodyParser());
app.use(session({ secret: 'xxx', key: 'user', cookie: { maxAge: 60000, secure: false } }));
app.use(passport.initialize());
app.use(passport.session());

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.get('/login', function (req, res) {
  console.log(req.isAuthenticated());
  res.send('Login');
});

app.get('/users', (req, res) => {
  console.log(req.isAuthenticated());
  res.send('aeae');
});

app.get('/auth',
  passport.authenticate('oidc'));

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
})]

everthing works fine, but my Strategy Callback is never called, so the code console.log(req.isAuthenticated()); always returns false!

keystore after creating Client object via registration client uri

I'm having a problem with Client.authorizationCallback for a specific client. The test client was registered via /reg API successfully to the provider which is basically oidc-provider module, I created a Client object by fromUri without a problem.

Tracing with debug log shows that the server side returned all data including id_token encrypted. It looks Client.decryptIdToken is failing with missing keystore in Client.

The other test client without id_token encryption option has no problem. Here a part of metadata for the client which has a problem, FYI. Please advise on this. Thanks.

"id_token_encrypted_response_alg" : "RSA1_5",
"jwks" : {
    "keys" : [ 
        {
            "kty" : "RSA",
            "kid" : "by8d5ZH8nCeQVVNfLRYXsyFWz-CQKiMIl3vcg6lyp1E",
            "e" : "AQAB",
            "n" : "igpjcaxuJwtX_TOQjHjQmLoSm8d9JS5UhkBtWb37_YFFdTDelZ8YbmrinqGR2GHsn8ZAasT4Y-wtrg6_NMvb2B3P4GDJZ5nbYBJmDkvpiCjM63M46Lm89RJ8STFAuxdVoUolBtxHtCVixHJh95BIHbMApaRJxpBF-dbvwU0n6WF6IOJLVipKfwZ70vgvu35_bwCVSk8SVq4ok9gVc6DsnxfP_6SuRPxJreYzxfjY4xT5emDw9dPF1zGFp8EQ5O-xAyeYrsGlfpIm0iM3E63DPOGEEZt8qjR0tPDF1t7x_5R2ZVkQ2p-MOd5kg2wKY-LjfOMoP0YlXUgE0yC7TaQmWw"
        }
    ]
},
"id_token_encrypted_response_enc" : "A128CBC-HS256",

What does "state mismatch" mean? And what causes it?

I'm struggling to get this component to work, using it with passport and express. Basically, I'm getting a backtrace from deep in the innards of the system, and I can't find how to pin down the issue.

It's likely it's something interacting with passport, but I've had to piece it together as there isn't a example for either express or passport, and I'm not sure what I'm doing. I only got this far with luck because authentication was running a redirect loop as well.

Any help or guidance would be very welcome.

Backtrace is as follows:

Error: state mismatch
    at Client.authorizationCallback (/mnt/data/git/turalt-demo/node_modules/openid-client/lib/client.js:279:29)
    at OpenIDConnectStrategy.authenticate (/mnt/data/git/turalt-demo/node_modules/openid-client/lib/passport_strategy.js:93:27)
    at attempt (/mnt/data/git/turalt-demo/node_modules/passport/lib/middleware/authenticate.js:361:16)
    at authenticate (/mnt/data/git/turalt-demo/node_modules/passport/lib/middleware/authenticate.js:362:7)
    at Layer.handle [as handle_request] (/mnt/data/git/turalt-demo/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:317:13)
    at /mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:335:12)
    at next (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:275:10)
    at Function.handle (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:174:3)
    at router (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:47:12)
    at Layer.handle [as handle_request] (/mnt/data/git/turalt-demo/node_modules/express/lib/router/layer.js:95:5)
    at trim_prefix (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:317:13)
    at /mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:284:7
    at Function.process_params (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:335:12)
    at next (/mnt/data/git/turalt-demo/node_modules/express/lib/router/index.js:275:10)

Why is validateIdToken() private?

You've got validateIdToken() documented in the code as private.

It would seem to me that an advantage of using JWTs is that you can then pass them to your other services to authenticate the user.

In those secondary services I would think you would want to validate the JWT by doing something similar to...

const token = req.header.authorization.slice('Bearer '.length);
client.validateIdToken(token)
.then(result => {
  // assert some other things about the user
});

Is it just an oversight that this is documented as private, or is there some reasoning behind this?

Any insight would be appreciated.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.