oidc-provider
oidc-provider is an OpenID Provider implementation of OpenID Connect. It allows to
export a complete Koa.js OpenID Provider implementation which you can mount to your existing Koa.js
applications or run standalone. This implementation does not force you into any data models or
persistance stores, instead it expects you to provide an adapter. A generic in memory adapter is
available to get you started.
The provided examples also implement simple user interaction views but those are not forced on you
as they do not come as part of the exported application, instead you are encouraged to implement
your own unique-looking and functioning user flows.
Table of Contents
Implemented specs & features
The following specifications are implemented by oidc-provider.
Get started
To run and experiment with an example server, clone the oidc-provider repo and install the dependencies:
$ git clone https://github.com/panva/node-oidc-provider.git oidc-provider
$ cd oidc-provider
$ npm install
$ node example
Visiting http://localhost:3000/.well-known/openid-configuration
will help you to discover how the
example is configured.
Otherwise just install the package in your app and follow the example use.
$ npm install oidc-provider --save
Configuration
const Provider = require('oidc-provider').Provider;
const issuer = 'http://localhost:3000';
const configuration = {
};
const oidc = new Provider(issuer, configuration);
Default configuration values.
Features
Discovery
const configuration = { features: { discovery: Boolean[true] } };
Exposes /.well-known/webfinger
and /.well-known/openid-configuration
endpoints. Contents of the
latter reflect your actual configuration, i.e. available claims, features and so on.
Note: when using koa-mount to slap the Provider on to an existing application you may want to have
these endpoints relative from your root, to see how (using koa-rewrite) check the
example.
Authorization claims
parameter
const configuration = { features: { claimsParameter: Boolean[false] } };
Enables the use and validations of claims
parameter as described in Core 1.0
and the discovery endpoint property claims_parameter_supported
set to true.
Token endpoint client_credentials
grant
const configuration = { features: { clientCredentials: Boolean[false] } };
Enables grant_type=client_credentials
to be used on the token endpoint. Note: client still has to
be allowed this grant.
Hint: allowing this grant together with token introspection and revocation is an easy and elegant
way to allow authorized access to some less sensitive backend actions.
Encryption features
const configuration = { features: { encryption: Boolean[false] } };
... userinfo, idtoken and request parameter depending on client configuration
Refresh tokens for everyone
const configuration = { features: { refreshToken: Boolean[false] } };
Every grant_type=authorization_code will result in refresh_token being issued (if a client also has
refresh_token part of it's announced grant_type
s). Also enables the grant_type=refresh_token
for
these clients.
Authorization request
parameter
const configuration = { features: { request: Boolean[false] } };
Enables the use and validations of request
parameter as described in
Core 1.0 and the discovery endpoint property
request_parameter_supported
set to true.
Authorization request_uri
parameter
const configuration = { features: { requestUri: Boolean[false] } };
Enables the use and validations of request_uri
parameter as described in
Core 1.0 and the discovery endpoint property
request_uri_parameter_supported
set to true.
To also enable require_request_uri_registration do this:
const configuration = { features: { requestUri: { requireRequestUriRegistration: true } } };
Introspection endpoint
const configuration = { features: { introspection: Boolean[false] } };
Enables the use of Introspection endpoint as described in RFC7662 for
tokens of type AccessToken, ClientCredentials and RefreshToken. When enabled
token_introspection_endpoint property of the discovery endpoint is true
, otherwise the property
is not sent. The use of this endpoint is covered by the same authz mechanism as the regular token
endpoint.
Revocation endpoint
const configuration = { features: { revocation: Boolean[false] } };
Enables the use of Revocation endpoint as described in RFC7009 for tokens of
type AccessToken, ClientCredentials and RefreshToken. When enabled
token_revocation_endpoint property of the discovery endpoint is true
, otherwise the property
is not sent. The use of this endpoint is covered by the same authz mechanism as the regular token
endpoint.
Session management features
const configuration = { features: { sessionManagement: Boolean[false] } };
Enables features described in Session Management 1.0 - draft26.
Dynamic registration features
const configuration = { features: { registration: Boolean[false] } };
Enables features described in Dynamic Client Registration 1.0.
Routes
You can change the default routes by providing a routes object
to the oidc-provider constructor.
const oidc = new Provider('http://localhost:3000', {
routes: {
authorization: '/authz',
certificates: '/jwks'
}
});
Keys (signing and encryption)
To add RSA or EC signing and encryption keys use the addKey
method on a oidc-provider instance.
This accepts a jwk formatted private key object and returns a Promise, resolved with
node-jose jose.JWK.Key
At the very least you must add one RSA key (and do yourself a favor and use at least 2048 bit). You
MAY provide the use
and kid
properties. When use
is ommited the key will be available for both
signing and encryption. When kid
is ommited it will be calculated according to
JSON Web Key (JWK) Thumbprint.
Persistance
The provided example and any new instance of oidc-provider will use the basic in-memory adapter for
storing issued tokens, codes and user sessions. This is fine for as long as you develop, configure
and generally just play around since every time you restart your process all information will be
lost. As soon as you cannot live with this limitation you will be required to provide an adapter
for oidc-provider to use.
const MyAdapter = require('./my_adapter');
const oidc = new Provider('http://localhost:3000', {
adapter: MyAdapter
});
The API oidc-provider expects is documented here. For reference see the
memory adapter and redis of
mongodb adapters. There's also a simple test
[redis,mongodb] you can use to
check your own implementation.
Clients
Clients can be managed programmatically or via out of bounds mechanisms using your provided Adapter.
At the very least you must provide client_id, client_secret and redirect_uris for each client. See
the rest of the available metadata here.
Note: each oidc-provider caches the clients once they are loaded (via either of the mechanisms),
when in need of client configuration "reload" you can purge this cache like so
oidc.get('Client').purge()
;
via Provider interface
To add pre-established clients use the addClient
method on a oidc-provider instance. This accepts
metadata object and returns a Promise, fulfilled with the added Client object, rejected with a
validation or other errors that may have been encountered.
const oidc = new Provider('http://localhost:3000');
const metadata = {
};
oidc.addClient(metadata).then(fulfillmentHandler, rejectionHandler);
via Adapter
Storing client metadata in your storage is recommended for distributed deployments. Also when you
want to provide a client configuration GUI or plan on changing this data often. Clients get loaded
! and validated ! when they first get loaded, any metadata validation error encountered during
this first load will be thrown and handled like any other context specific errors.
Events
The oidc-provider instance is an event emitter, this
is always the instance. In events where ctx
(koa
request context) is passed to the listener ctx.oidc
holds additional details like recognized
parameters, loaded client or session.
server_error
oidc.on('server_error', function (error, ctx) { }
)
Emitted when an exception is thrown or promise rejected from either the Provider or your provided
adapters. If it comes from the library you should probably report it.
authorization.success
oidc.on('authorization.success', function (ctx) { }
)
Emitted with every successful authorization request. Useful i.e. for collecting metrics or
triggering any action you need to execute after succeeded authorization.
authorization.error
oidc.on('authorization.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the authorization
endpoint.
grant.success
oidc.on('grant.success', function (ctx) { }
)
Emitted with every successful grant request. Useful i.e. for collecting metrics or triggering any
action you need to execute after succeeded grant.
grant.error
oidc.on('grant.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the grant
endpoint.
certificates.error
oidc.on('certificates.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the certificates
endpoint.
discovery.error
oidc.on('discovery.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the discovery
endpoint.
introspection.error
oidc.on('introspection.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the introspection
endpoint.
revocation.error
oidc.on('revocation.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the revocation
endpoint.
registration.error
oidc.on('registration.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the registration
endpoint.
userinfo.error
oidc.on('userinfo.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the userinfo
endpoint.
check_session.error
oidc.on('check_session.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the check_session
endpoint.
end_session.error
oidc.on('end_session.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the end_session
endpoint.
webfinger.error
oidc.on('webfinger.error', function (error, ctx) { }
)
Emitted when a handled error is encountered in the webfinger
endpoint.
token.issued
oidc.on('token.issued', function (token) { }
)
Emitted when a token is issued. All tokens extending OAuthToken
emit this event.
token can be one of AccessToken
, AuthorizationCode
,
ClientCredentials
, RefreshToken
.
token.consumed
oidc.on('token.consumed', function (token) { }
)
Emitted when a token (actually just AuthorizationCode) is used.
token.revoked
oidc.on('token.revoked', function (token) { }
)
Emitted when a token is about to be revoked.
grant.revoked
oidc.on('grant.revoked', function (grantId) { }
)
Emitted when tokens resulting from a single grant are about to be revoked.
grantId
is uuid formatted string. Use this to cascade the token revocation in cases where your
adapter cannot provides functionality.
Certification
OpenID Certified™ by Filip Skokan to the OP Basic, OP Implicit, OP Hybrid,
OP Config and OP Dynamic profiles of the OpenID Connect™ protocol.