panva / node-openid-client Goto Github PK
View Code? Open in Web Editor NEWOpenID Certified™ Relying Party (OpenID Connect/OAuth 2.0 Client) implementation for Node.js.
License: MIT License
OpenID Certified™ Relying Party (OpenID Connect/OAuth 2.0 Client) implementation for Node.js.
License: MIT License
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!
Install of latest client fails with following error.
> npm i openid-client
npm ERR! cb() never called!
Previous version is fine.
Hi, how can i use request for openid-client.
Also how can i setup a proxy for the issuer please?
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.
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?
I ended up needing to fork this library to replace got
with request
, as got
doesn't play very well with tunnelling proxies. I created a shim around request to expose the same API to the application. Would you consider making the http client a config option, so others could use this if they wanted?
https://github.com/JoshBarr/node-openid-client/blob/master/lib/request.js
thanks heaps!
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.
Nice work!
I'm wondering if you are planning to add support for grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
and/or if you will accept some contributions
Tnx
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?
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.
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()
?
It looks like one can't access custom discovery props because they are filtered: https://github.com/panva/node-openid-client/blob/master/lib/issuer.js#L47.
It seems like custom discovery props should be accessible in some way. Perhaps the raw discovery response can be exposed by a getter on the Issuer
.
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,
}
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
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.
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.
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?
I'd like to specify more than one in response_types and scope in Passport Strategy, but I do not seem to be able to do it.
For example, when I make new client with response_types: ['id_token', 'token'], scope: ['openid', 'email', 'proflie'],
It seems that response_types = 'id_token', scope = 'openid'.
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 :-)
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
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);
});
});
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! :(
Is there a way to setup the token request to include the client_id and client_secret? I'm looking to use this with Twitch, which requires these items in the body for both authorization and the token request.
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 😄
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?
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 :)
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.
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.
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]
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!
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?
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)
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",
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;
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.
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:
In passport strategy file creating session key can be updated to this with a null check..
const hostname = url.parse(issuer.issuer).hostname || issuer.issuer;
const sessionKey = oidc:${hostname}
;
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.
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);
});
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.
I think it would be nice to have a function to return the script for processing fragments to User Agent, as shown in OpenID Connect Core 1.0 15.5.3.
What do you think?
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.
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
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?
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)
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);
});
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.
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 }
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.