express-openid-connect
Advanced tools
Comparing version 0.4.0 to 0.5.0
189
API.md
@@ -1,146 +0,117 @@ | ||
# API | ||
# Public API | ||
Please see the [Getting Started section of the README](https://github.com/auth0/express-openid-connect#getting-started) for how to apply configuration options. | ||
## Configuration Keys | ||
## openidClient.auth parameters | ||
Please see the [Getting Started section of the README](https://github.com/auth0/express-openid-connect#getting-started) for examples of how to apply the configuration options to the `auth()` middleware. | ||
In general, you won't need to configure this middleware besides the required parameters that can be specified through environment variables. | ||
### Required Keys | ||
| Name | Default | Description | | ||
|---------------------|---------------------------------|--------------------------------------------------------------------------------| | ||
| issuerBaseURL | `env.ISSUER_BASE_URL` | The url address for the token issuer. | | ||
| baseURL | `env.BASE_URL` | The url of the web application where you are installing the router. | | ||
| clientID | `env.CLIENT_ID` | The client id. | | ||
| clientSecret | `env.CLIENT_SECRET` | The client secret, only required for some grants. | | ||
| clockTolerance | `5` | The clock's tolerance in seconds for token verification. | | ||
| getUser | `tokenSet => tokenSet.claims()` | An async function receiving a tokenset and returning the profile for `req.openid.user`. | | ||
| required | `true` | If true requires authentication for all the routes in the stack. You can also provide a function to determine if is required based on the request. | | ||
| handleUnauthorizedErrors | `true` | Install a middleware that handles Unauthorized/401 errors by triggering the login process. | | ||
| routes | `true` | Installs the `GET /login` and `GET /logout` route. | | ||
| idpLogout | `false` | Logout the user from the identity provider on logout | | ||
| auth0Logout | `false` | Enable Auth0's non-compliant logout feature, only if Auth0 can be detected and the Auth0 instance does not support OpenID Connect session management. | | ||
| authorizationParams | See bellow | The parameters for the authorization call. | | ||
The `auth()` middleware has a few configuration keys that are required for initialization. | ||
Default value for `authorizationParams` is: | ||
- **`baseURL`** - The root URL for the application router. This can be set automatically with a `BASE_URL` variable in your environment. | ||
- **`clientID`** - The Client ID for your application. This can be set automatically with a `CLIENT_ID` variable in your environment. | ||
- **`issuerBaseURL`** - The root URL for the token issuer with no trailing slash. In Auth0, this is your Application's **Domain** prepended with `https://`. This can be set automatically with an `ISSUER_BASE_URL` variable in your environment. | ||
```javascript | ||
{ | ||
response_type: 'id_token', | ||
response_mode: 'form_post', | ||
scope: 'openid profile email' | ||
} | ||
``` | ||
If you are using a response type that includes `code` (typically combined with an `audience` parameter), you will need an additional key: | ||
Commonly used `authorizationParams`: | ||
- **`clientSecret`** - The Client ID for your application. This can be set automatically with a `CLIENT_SECRET` variable in your environment. | ||
| Name | Default | Description | | ||
|---------------------|------------------------|--------------------------------------------------------------------------------------------------------------| | ||
| response_type | **Required** | The desired authorization processing flow, including what parameters are returned from the endpoints used. | | ||
| response_mode | `undefined` / optional | The mechanism to be used for returning Authorization Response parameters from the Authorization Endpoint. | | ||
| scope | `openid profile email` | The scope of the access token. | | ||
| audience | `undefined` / optional | The audience for the access token. | | ||
### Optional Keys | ||
## openidClient.requiresAuth | ||
Additional configuration keys that can be passed to `auth()` on initialization: | ||
The `requiresAuth()` middleware protects specific application routes: | ||
- **`auth0Logout`** - Boolean value to enable Auth0's logout feature. Default is `false`. | ||
- **`authorizationParams`** - Object that describes the authorization server request. [See below](#authorization-params-key) for defaults and more details. | ||
- **`clockTolerance`** - Integer value for the system clock's tolerance (leeway) in seconds for ID token verification. Default is `60`. | ||
- **`getUser`** - Asynchronous function that receives a token set and returns the profile for `req.openid.user`. This runs on each application page load for authenticated users. Default is [here](lib/getUser.js). | ||
- **`errorOnRequiredAuth`** - Boolean value to throw a `Unauthorized 401` error instead of triggering the login process for routes that require authentication. Default is `false`. | ||
- **`httpOptions`** - Default options object used for all HTTP calls made by the library ([possible options](https://github.com/sindresorhus/got/tree/v9.6.0#options)). Default is empty. | ||
- **`idpLogout`** - Boolean value to log the user out from the identity provider on application logout. Requires the issuer to provide a `end_session_endpoint` value. Default is `false`. | ||
- **`loginPath`** - Relative path to application login. Default is `/login`. | ||
- **`logoutPath`** - Relative path to application logout. Default is `/logout`. | ||
- **`redirectUriPath`** - Relative path to the application callback to process the response from the authorization server. This value is combined with the `baseUrl` and sent to the authorize endpoint as the `redirectUri` parameter. Default is `/callback`. | ||
- **`required`** - Use a boolean value to require authentication for all routes. Pass a function instead to base this value on the request. Default is `true`. | ||
- **`routes`** - Boolean value to automatically install the login and logout routes. See [the examples](EXAMPLES.md) for more information on how this key is used. Default is `true`. | ||
```javascript | ||
const { auth, requiresAuth } = require('express-openid-connect'); | ||
app.use( auth( { required: false } ) ); | ||
app.use( '/admin', requiresAuth() ); | ||
``` | ||
### Authorization Params Key | ||
If all endpoints require the user to be logged in, the default `auth` middleware protects you from this: | ||
The `authorizationParams` key defines the URL parameters used when redirecting users to the authorization server to log in. If this key is not provided by your application, its default value will be: | ||
```javascript | ||
app.use( auth( { required: true } ) ); | ||
```js | ||
{ | ||
response_type: "id_token", | ||
response_mode: "form_post", | ||
scope: "openid profile email" | ||
} | ||
``` | ||
## Session and Context | ||
A new object can be passed in to change what is returned from the authorization server depending on your specific scenario. | ||
The middleware stores the [openid-client TokenSet](https://github.com/panva/node-openid-client/blob/master/docs/README.md#tokenset) in the user's session. | ||
For example, to receive an access token for an API, you could initialize like the sample below. Note that `response_mode` can be omitted because the OAuth2 default mode of `query` is fine: | ||
Every `req` object is augmented with the following properties when the request is authenticated | ||
```js | ||
app.use(auth({ | ||
authorizationParams: { | ||
response_type: "code", | ||
scope: "openid profile email read:reports", | ||
audience: "https://your-api-identifier" | ||
} | ||
})); | ||
``` | ||
- `req.openid.user`: contains the user information, use this if you need display an attribute of the user. You can change what's end up here by using the `getUser` parameter of the `auth` middleware. | ||
- `req.openid.tokens`: is the instance of [TokenSet](https://github.com/panva/node-openid-client/blob/master/docs/README.md#tokenset). | ||
- `req.openid.client`: is an instance of te [OpenID Client](https://github.com/panva/node-openid-client/blob/master/docs/README.md#client). | ||
- `req.isAuthenticated()`: returns true if the request is authenticated. | ||
Additional custom parameters can be added as well: | ||
If the request is not authenticated, `req.openid` is `undefined`. | ||
```js | ||
app.use(auth({ | ||
authorizationParams: { | ||
// Note: you need to provide required parameters if this object is set. | ||
response_type: "id_token", | ||
response_mode: "form_post", | ||
scope: "openid profile email" | ||
Every `res` object gets the following methods: | ||
// Additional parameters | ||
acr_value: "tenant:test-tenant", | ||
custom_param: "custom-value" | ||
} | ||
})); | ||
``` | ||
- `res.openid.login(params)`: trigger an authentication request from any route. It receives the following parameters: | ||
- `params.returnTo`: The url to return to after authentication. Defaults to the current url for GETs and `baseURL` for other methods. | ||
- `params.authorizationParams`: additional parameters for the authorization call. | ||
- `res.openid.logout(params)`: trigger the openid connect logout if supporter by the issuer. | ||
- `params.returnTo`: The url to return to after sign out. Defaults to the `baseURL` for other methods. | ||
## `requiresAuth()` | ||
## Authorization handling | ||
The `requiresAuth()` function is an optional middleware that protects specific application routes when the `required` configuration key is set to `false`: | ||
By default the library triggers the login process when authentication is required. | ||
An anonymous request to the home page in this case will trigger the login process: | ||
```js | ||
app.use(auth()); // Remember that required is true by default | ||
app.get('/', (req, res) => res.render('home')); | ||
```javascript | ||
const { auth, requiresAuth } = require('express-openid-connect'); | ||
app.use( auth( { required: false } ) ); | ||
app.use( '/admin', requiresAuth(), (req, res) => res.render('admin') ); | ||
``` | ||
The same happens in this case: | ||
Using `requiresAuth()` on its own without initializing `auth()` will throw a `401 Unauthorized` error instead of triggering the login process: | ||
```js | ||
app.use(auth()); // Remember that required is true by default | ||
// app.use(auth({required: true})); | ||
app.get('/', requiresAuth(), (req, res) => res.render('home')); | ||
``` | ||
If you remove the `auth()` middleware above like this: | ||
## Session and Context | ||
```js | ||
// app.use(auth()); // Remember that required is true by default | ||
app.get('/', requiresAuth(), (req, res) => res.render('home')); | ||
``` | ||
This library adds properties and methods to the request and response objects used within route handling. | ||
Instead of triggering the login process we get a 401 Unauthorized error. | ||
### Request | ||
It is a best practice to decouple your application logic from this library. If you need to raise a 401 error on your own logic and `requiresAuth` is not enough, you can add the `unauthorizedHandler` from this library: | ||
Every request object (typically named `req` in your route handler) is augmented with the following when the request is authenticated. If the request is not authenticated, `req.openid` is `undefined`. | ||
```js | ||
const { | ||
auth, | ||
requiresAuth, | ||
unauthorizedHandler | ||
} = require('express-openid-connect'); | ||
- **`req.openid.user`** - Contains the user information returned from the authorization server. You can change what is provided here by using the `getUser` configuration key. | ||
- **`req.openid.tokens`** - Is the [TokenSet](https://github.com/panva/node-openid-client/blob/master/docs/README.md#tokenset) instance obtained during login. | ||
- **`req.openid.client`** - Is the [OpenID Client](https://github.com/panva/node-openid-client/blob/master/docs/README.md#client) instance that can be used for additional OAuth2 and OpenID calls. See [the examples](EXAMPLES.md) for more information on how this is used. | ||
- **`req.isAuthenticated()`** - Returns true if the request is authenticated. | ||
app.use(auth()); | ||
### Response | ||
// your routes go here | ||
app.get('/a-route', (req, res, next) => { | ||
if (condition) { | ||
return next(new UnauthorizedError('unauthorized because of xyz')); | ||
} | ||
}); | ||
Every response object (typically named `res` in your route handler) is augmented with the following: | ||
//trigger login transactions on 401 errors. | ||
app.use(unauthorizedHandler()); | ||
``` | ||
If you need an special logic for handling 401s, including the errors raised by this library, you can set `errorOnRequiredAuth` to `true` like this: | ||
```js | ||
const { auth, requiresAuth } = require('express-openid-connect'); | ||
app.use(auth({ errorOnRequiredAuth: true })); | ||
// your routes go here | ||
//handle unauthorized errors with the unauthorizedHandler or | ||
//with your own middleware like this: | ||
app.use((err, req, res, next) => { | ||
if (err.statusCode === 401) { | ||
return res.openid.login(); //trigger the login process like the `unauthorizedHandler`. | ||
} | ||
next(err); | ||
}); | ||
``` | ||
- **`res.openid.login({})`** - trigger an authentication request from any route. It receives an object with the following keys: | ||
- `returnTo`: The URL to return to after authentication. Defaults to the current URL for `GET` routes and `baseURL` for other methods. | ||
- `authorizationParams`: Additional parameters for the authorization call. | ||
- **`res.openid.logout({})`** - trigger the openid connect logout if supporter by the issuer. It receives an object with the following key: | ||
- `returnTo`: The URL to return to after signing out at the authorization server. Defaults to the `baseURL`. |
# CHANGELOG | ||
## [v0.5.0](https://github.com/auth0/express-openid-connect/tree/v0.5.0) (2019-10-17) | ||
[Full Changelog](https://github.com/auth0/express-openid-connect/compare/v0.4.0...v0.5.0) | ||
**Closed issues** | ||
- Removal of automatic refresh [\#11](https://github.com/auth0/express-openid-connect/issues/11) | ||
**Added** | ||
- Add configurable HTTP options [\#29](https://github.com/auth0/express-openid-connect/pull/29) ([joshcanhelp](https://github.com/joshcanhelp)) | ||
- add typescript types [\#27](https://github.com/auth0/express-openid-connect/pull/27) ([jbarrus](https://github.com/jbarrus)) | ||
- Add telemetry to HTTP requests [\#23](https://github.com/auth0/express-openid-connect/pull/23) ([joshcanhelp](https://github.com/joshcanhelp)) | ||
- feat: allow custom login and logout paths [\#14](https://github.com/auth0/express-openid-connect/pull/14) ([joshcanhelp](https://github.com/joshcanhelp)) | ||
**Changed** | ||
- Update default leeway and re-write API documentation [\#30](https://github.com/auth0/express-openid-connect/pull/30) ([joshcanhelp](https://github.com/joshcanhelp)) | ||
## [v0.4.0](https://github.com/auth0/express-openid-connect/tree/v0.4.0) (2019-09-26) | ||
@@ -4,0 +22,0 @@ [Full Changelog](https://github.com/auth0/express-openid-connect/compare/v0.3.0...v0.4.0) |
119
EXAMPLES.md
### Example 1 | ||
# Examples | ||
## 1. Basic Setup | ||
The simplest use case for this middleware: | ||
@@ -8,3 +10,2 @@ | ||
# .env | ||
ISSUER_BASE_URL=https://YOUR_DOMAIN | ||
@@ -18,8 +19,7 @@ CLIENT_ID=YOUR_CLIENT_ID | ||
```javascript | ||
// app.js | ||
const { auth } = require('express-openid-connect'); | ||
const session = require('cookie-session'); | ||
app.use(express.urlencoded({ | ||
extended: false | ||
})); | ||
app.use(express.urlencoded({ extended: false })); | ||
@@ -43,10 +43,44 @@ app.use(session({ | ||
- Every route after the `auth()` middleware requires authentication. | ||
- If a user try to access a resource without being authenticated, the application will trigger the authentication process. After completion the user is redirected back to the resource. | ||
- The application creates `GET /login` and `GET /logout` routes for easy linking. | ||
- If a user tries to access a resource without being authenticated, the application will redirect the user to log in. After completion the user is redirected back to the resource. | ||
- The application creates `/login` and `/logout` `GET` routes. | ||
### Example 2 | ||
## 2. Require authentication for specific routes | ||
If you need to customize the routes, you can opt-out from the default routes and handle this manually: | ||
If your application has routes accessible to anonymous users, you can enable authorization per routes: | ||
```js | ||
const { auth, requiresAuth } = require('express-openid-connect'); | ||
app.use(auth({ | ||
required: false | ||
})); | ||
// Anyone can access the homepage | ||
app.use('/', (req, res) => res.render('home')); | ||
// Require routes under the /admin/ prefix to check authentication. | ||
app.use('/admin/users', requiresAuth(), (req, res) => res.render('admin-users')); | ||
app.use('/admin/posts', requiresAuth(), (req, res) => res.render('admin-posts')); | ||
``` | ||
Another way to configure this scenario: | ||
```js | ||
const { auth } = require('express-openid-connect'); | ||
//initialization | ||
app.use(auth({ | ||
required: req => req.originalUrl.startsWith('/admin/') | ||
})); | ||
app.use('/', (req, res) => res.render('home')); | ||
app.use('/admin/users', (req, res) => res.render('admin-users')); | ||
app.use('/admin/posts', (req, res) => res.render('admin-posts')); | ||
``` | ||
## 3. Route Customization | ||
If you need to customize the routes, you can opt-out from the default routes and write your own route handler: | ||
```js | ||
app.use(auth({ routes: false })); | ||
@@ -58,26 +92,65 @@ | ||
Please note that both of these routes are completely optional and not required. Trying to access any protected resource triggers the authentication process if required. | ||
... or you can define specific routes in configuration keys where the default handler will run: | ||
### Example 3 | ||
```js | ||
app.use(auth({ | ||
redirectUriPath: '/custom-callback-path', | ||
loginPath: '/custom-login-path', | ||
logoutPath: '/custom-logout-path', | ||
})); | ||
``` | ||
If your application has routes accessible to anonymous users, you can enable authorization per routes: | ||
Please note that both of these routes are completely optional and not required. Trying to access any protected resource triggers a redirect directly to Auth0 to login. | ||
```js | ||
const { auth, requiresAuth } = require('express-openid-connect'); | ||
## 4. Using refresh tokens | ||
app.use(auth({ required: false })); | ||
Refresh tokens can be requested along with access tokens using the `offline_access` scope during login: | ||
// Require every route under the /admin prefix to check authentication. | ||
app.use('/admin', requiresAuth());; | ||
```js | ||
app.use(auth({ | ||
authorizationParams: { | ||
response_type: 'code id_token', | ||
response_mode: 'form_post', | ||
audience: process.env.API_URL, | ||
scope: 'openid profile email read:reports offline_access' | ||
} | ||
})); | ||
``` | ||
Another way to configure this scenario: | ||
On a route that calls an API, check for an expired token and attempt a refresh: | ||
```js | ||
const { auth } = require('express-openid-connect'); | ||
app.get('/route-that-calls-an-api', async (req, res, next) => { | ||
//initialization | ||
app.use(auth({ | ||
required: req => req.originalUrl.startsWith('/admin') | ||
})); | ||
let apiData = {}; | ||
let tokenSet = req.openid.tokens; | ||
if (tokenSet.expired() && tokenSet.refresh_token) { | ||
try { | ||
tokenSet = await req.openid.client.refresh(tokenSet); | ||
} catch(err) { | ||
next(err); | ||
} | ||
tokenSet.refresh_token = req.openid.tokens.refresh_token; | ||
req.openid.tokens = tokenSet; | ||
} | ||
try { | ||
apiData = await request( | ||
process.env.API_URL, | ||
{ | ||
headers: { authorization: `Bearer ${tokenSet.access_token}` }, | ||
json: true | ||
} | ||
); | ||
} catch(err) { | ||
next(err); | ||
} | ||
res.render('api-data-template', { | ||
user: req.openid && req.openid.user, | ||
apiData | ||
}); | ||
}); | ||
``` |
@@ -7,33 +7,45 @@ const { Issuer, custom } = require('openid-client'); | ||
custom.setHttpOptionsDefaults({ | ||
headers: { | ||
'User-Agent': `${pkg.name}/${pkg.version} (${pkg.homepage})` | ||
}, | ||
timeout: 4000 | ||
}); | ||
const telemetryHeader = { | ||
name: 'express-oidc', | ||
version: pkg.version, | ||
env: { | ||
node: process.version | ||
} | ||
}; | ||
async function get(config) { | ||
const authorizeParams = config.authorizationParams; | ||
const issuer = await Issuer.discover(config.issuerBaseURL); | ||
if (Array.isArray(issuer.response_types_supported) && | ||
!issuer.response_types_supported.includes(authorizeParams.response_type)) { | ||
throw new Error(`The issuer doesn't support the response_type ${authorizeParams.response_type} | ||
Supported types: | ||
- ${issuer.response_types_supported.sort().join('\n- ')} | ||
`); | ||
const issuerTokenAlgs = Array.isArray(issuer.id_token_signing_alg_values_supported) ? | ||
issuer.id_token_signing_alg_values_supported : []; | ||
if (!issuerTokenAlgs.includes(config.idTokenAlg)) { | ||
throw new Error( | ||
`ID token algorithm "${config.idTokenAlg}" is not supported by the issuer. ` + | ||
`Supported ID token algorithms are: "${issuerTokenAlgs.join('", "')}". ` | ||
); | ||
} | ||
if (authorizeParams.response_mode && Array.isArray(issuer.response_modes_supported) && | ||
!issuer.response_modes_supported.includes(authorizeParams.response_mode)) { | ||
throw new Error(`The issuer doesn't support the response_mode ${authorizeParams.response_mode} | ||
Supported response modes: | ||
- ${issuer.response_modes_supported.sort().join('\n- ')} | ||
`); | ||
const configRespType = config.authorizationParams.response_type; | ||
const issuerRespTypes = Array.isArray(issuer.response_types_supported) ? issuer.response_types_supported : []; | ||
if (!issuerRespTypes.includes(configRespType)) { | ||
throw new Error( | ||
`Response type "${configRespType}" is not supported by the issuer. ` + | ||
`Supported response types are: "${issuerRespTypes.join('", "')}". ` | ||
); | ||
} | ||
const configRespMode = config.authorizationParams.response_mode; | ||
const issuerRespModes = Array.isArray(issuer.response_modes_supported) ? issuer.response_modes_supported : []; | ||
if (configRespMode && ! issuerRespModes.includes(configRespMode)) { | ||
throw new Error( | ||
`Response mode "${configRespMode}" is not supported by the issuer. ` + | ||
`Supported response modes are "${issuerRespModes.join('", "')}". ` | ||
); | ||
} | ||
const client = new issuer.Client({ | ||
client_id: config.clientID, | ||
client_secret: config.clientSecret | ||
client_secret: config.clientSecret, | ||
id_token_signed_response_alg: config.idTokenAlg, | ||
}); | ||
@@ -56,2 +68,13 @@ | ||
let httpOptions = config.httpOptions || {}; | ||
httpOptions.headers = Object.assign( | ||
// Allow configuration to override user agent header. | ||
{'User-Agent': `${pkg.name}/${pkg.version}`}, | ||
httpOptions.headers || {}, | ||
// Do not allow overriding telemetry. | ||
{'Auth0-Client': Buffer.from(JSON.stringify(telemetryHeader)).toString('base64')} | ||
); | ||
custom.setHttpOptionsDefaults(httpOptions); | ||
client[custom.clock_tolerance] = config.clockTolerance; | ||
@@ -58,0 +81,0 @@ |
@@ -20,2 +20,3 @@ const Joi = require('@hapi/joi'); | ||
const paramsSchema = Joi.object().keys({ | ||
httpOptions: Joi.object().optional(), | ||
issuerBaseURL: Joi.alternatives([ Joi.string().uri(), Joi.string().hostname() ]).required(), | ||
@@ -25,4 +26,5 @@ baseURL: Joi.string().uri().required(), | ||
clientSecret: Joi.string().optional(), | ||
idTokenAlg: Joi.string().not('none').optional().default('RS256'), | ||
authorizationParams: Joi.object().optional(), | ||
clockTolerance: Joi.number().optional().default(5), | ||
clockTolerance: Joi.number().optional().default(60), | ||
getUser: Joi.func().optional().default(getUser), | ||
@@ -34,2 +36,4 @@ required: Joi.alternatives([ Joi.func(), Joi.boolean()]).optional().default(true), | ||
redirectUriPath: Joi.string().optional().default('/callback'), | ||
loginPath: Joi.string().optional().default('/login'), | ||
logoutPath: Joi.string().optional().default('/logout'), | ||
idpLogout: Joi.boolean().optional().default(false) | ||
@@ -81,7 +85,11 @@ .when('auth0Logout', { is: true, then: Joi.boolean().optional().default(true) }) | ||
const missingClientSecret = !config.clientSecret && | ||
config.authorizationParams.response_type.split(' ').includes('code'); | ||
// Code grant requires a client secret to exchange the code for tokens | ||
const responseTypeHasCode = config.authorizationParams.response_type.split(' ').includes('code'); | ||
if (responseTypeHasCode && !config.clientSecret) { | ||
throw new Error('"clientSecret" is required for response_type code'); | ||
} | ||
if(missingClientSecret) { | ||
throw new Error('"clientSecret" is required for response_type code and response_mode query'); | ||
// HS256 ID tokens require a client secret to validate the signature. | ||
if ('HS' === config.idTokenAlg.substring(0,2) && !config.clientSecret) { | ||
throw new Error('"clientSecret" is required for ID tokens with HS algorithms'); | ||
} | ||
@@ -88,0 +96,0 @@ |
@@ -25,8 +25,2 @@ /** | ||
/** | ||
* Authorization Response parameters are encoded in | ||
* the fragment added to the redirect_uri when redirecting back to the Client. | ||
*/ | ||
Fragment: 'fragment', | ||
/** | ||
* Authorization Response parameters are encoded as HTML form values | ||
@@ -33,0 +27,0 @@ * that are auto-submitted in the User Agent, and thus are transmitted via the HTTP POST method |
@@ -5,4 +5,2 @@ const express = require('express'); | ||
const { get: getConfig } = require('../lib/config'); | ||
const memoize = require('p-memoize'); | ||
const fs = require('fs'); | ||
const { get: getClient } = require('../lib/client'); | ||
@@ -12,4 +10,2 @@ const requiresAuth = require('./requiresAuth'); | ||
const getRepostView = memoize(() => fs.readFileSync(__dirname + '/../views/repost.html')); | ||
/** | ||
@@ -23,3 +19,3 @@ * Returns a router with two routes /login and /callback | ||
* @param {string} [params.clientSecret] The client secret, only required for some grants. | ||
* @param {string} [params.clockTolerance=5] The clock's tolerance in seconds for token verification. | ||
* @param {string} [params.clockTolerance] The clock's tolerance in seconds for token verification. | ||
* @param {Function} [params.getUser] An async function receiving a tokenset and returning the profile for req.user. | ||
@@ -70,10 +66,9 @@ * @param {boolean|Function} [params.required=true] a boolean to indicate that every route after this middleware requires authentication or | ||
if (config.routes) { | ||
router.get('/login', (req, res) => { | ||
router.get(config.loginPath, (req, res) => { | ||
res.openid.login({ returnTo: config.baseURL }); | ||
}); | ||
router.get('/logout', (req, res) => res.openid.logout()); | ||
router.get(config.logoutPath, (req, res) => res.openid.logout()); | ||
} | ||
let callbackMethod; | ||
let repost; | ||
@@ -87,14 +82,4 @@ switch (authorizeParams.response_mode) { | ||
break; | ||
case 'fragment': | ||
callbackMethod = 'post'; | ||
repost = true; | ||
break; | ||
default: | ||
if (/token/.test(authorizeParams.response_type)) { | ||
callbackMethod = 'post'; | ||
repost = true; | ||
} | ||
else { | ||
callbackMethod = 'get'; | ||
} | ||
callbackMethod = 'get'; | ||
} | ||
@@ -136,9 +121,2 @@ | ||
if (repost) { | ||
router.get('/callback', async (req, res) => { | ||
res.set('Content-Type', 'text/html'); | ||
res.send(getRepostView()); | ||
}); | ||
} | ||
if (config.required) { | ||
@@ -145,0 +123,0 @@ const requiresAuthMiddleware = requiresAuth(); |
{ | ||
"name": "express-openid-connect", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "An Express.js middleware to protect OpenID Connect web applications.", | ||
"homepage": "https://github.com/auth0/express-openid-connect", | ||
"license": "MIT", | ||
"author": "José F. Romaniello <jfromaniello@gmail.com> (https://joseoncode.com)", | ||
"author": "Auth0 <support@auth0.com>", | ||
"main": "index.js", | ||
@@ -18,3 +18,3 @@ "scripts": { | ||
"http-errors": "^1.7.3", | ||
"openid-client": "^3.7.2", | ||
"openid-client": "^3.7.3", | ||
"p-memoize": "^3.1.0", | ||
@@ -24,2 +24,3 @@ "url-join": "^4.0.1" | ||
"devDependencies": { | ||
"@types/express": "^4.17.1", | ||
"body-parser": "^1.19.0", | ||
@@ -32,8 +33,8 @@ "chai": "^4.2.0", | ||
"jsonwebtoken": "^8.5.1", | ||
"mocha": "^6.2.0", | ||
"nock": "^11.3.5", | ||
"mocha": "^6.2.1", | ||
"nock": "^11.4.0", | ||
"pem-jwk": "^2.0.0", | ||
"proxyquire": "^2.1.3", | ||
"request-promise-native": "^1.0.7", | ||
"selfsigned": "^1.10.6", | ||
"selfsigned": "^1.10.7", | ||
"sinon": "^7.5.0" | ||
@@ -40,0 +41,0 @@ }, |
@@ -14,7 +14,4 @@ # Express OpenID Connect | ||
[![Build Status](https://travis-ci.org/auth0/express-openid-connect.svg?branch=master)](https://travis-ci.org/auth0/express-openid-connect) | ||
[![NPM version](https://img.shields.io/npm/v/express-openid-connect.svg?style=flat-square)](https://npmjs.org/package/express-openid-connect) | ||
[![Downloads](https://img.shields.io/npm/dm/express-openid-connect.svg.svg?style=flat-square)](https://npmjs.org/package/express-openid-connect.svg) | ||
## Table of Contents | ||
@@ -72,5 +69,6 @@ | ||
app.use(auth({ | ||
required: true, | ||
issuerBaseURL: 'https://YOUR_DOMAIN', | ||
baseURL: 'YOUR_CLIENT_ID', | ||
clientID: 'https://YOUR_APPLICATION_ROOT_URL' | ||
baseURL: 'https://YOUR_APPLICATION_ROOT_URL', | ||
clientID: 'YOUR_CLIENT_ID' | ||
})); | ||
@@ -77,0 +75,0 @@ ``` |
const assert = require('chai').assert; | ||
const url = require('url'); | ||
const fs = require('fs'); | ||
const request = require('request-promise-native').defaults({ | ||
@@ -24,5 +23,5 @@ simple: false, | ||
router = expressOpenid.auth({ | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
required: false | ||
@@ -51,5 +50,5 @@ }); | ||
const parsed = url.parse(res.headers.location, true); | ||
assert.equal(parsed.hostname, 'flosser.auth0.com'); | ||
assert.equal(parsed.hostname, 'test.auth0.com'); | ||
assert.equal(parsed.pathname, '/authorize'); | ||
assert.equal(parsed.query.client_id, '123'); | ||
assert.equal(parsed.query.client_id, '__test_client_id__'); | ||
@@ -59,3 +58,3 @@ assert.equal(parsed.query.scope, 'openid profile email'); | ||
assert.equal(parsed.query.response_mode, 'form_post'); | ||
assert.equal(parsed.query.redirect_uri, 'https://myapp.com/callback'); | ||
assert.equal(parsed.query.redirect_uri, 'https://example.org/callback'); | ||
assert.property(parsed.query, 'nonce'); | ||
@@ -77,5 +76,5 @@ assert.property(parsed.query, 'state'); | ||
router = expressOpenid.auth({ | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
authorizationParams: { | ||
@@ -97,9 +96,9 @@ response_mode: undefined, | ||
assert.equal(parsed.hostname, 'flosser.auth0.com'); | ||
assert.equal(parsed.hostname, 'test.auth0.com'); | ||
assert.equal(parsed.pathname, '/authorize'); | ||
assert.equal(parsed.query.client_id, '123'); | ||
assert.equal(parsed.query.client_id, '__test_client_id__'); | ||
assert.equal(parsed.query.scope, 'openid profile email'); | ||
assert.equal(parsed.query.response_type, 'none'); | ||
assert.equal(parsed.query.response_mode, undefined); | ||
assert.equal(parsed.query.redirect_uri, 'https://myapp.com/callback'); | ||
assert.equal(parsed.query.redirect_uri, 'https://example.org/callback'); | ||
assert.property(parsed.query, 'nonce'); | ||
@@ -120,6 +119,6 @@ assert.property(parsed.query, 'state'); | ||
router = router = expressOpenid.auth({ | ||
clientID: '123', | ||
clientSecret: '456', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
clientSecret: '__test_client_secret__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
authorizationParams: { | ||
@@ -141,9 +140,9 @@ response_mode: undefined, | ||
assert.equal(parsed.hostname, 'flosser.auth0.com'); | ||
assert.equal(parsed.hostname, 'test.auth0.com'); | ||
assert.equal(parsed.pathname, '/authorize'); | ||
assert.equal(parsed.query.client_id, '123'); | ||
assert.equal(parsed.query.client_id, '__test_client_id__'); | ||
assert.equal(parsed.query.scope, 'openid profile email'); | ||
assert.equal(parsed.query.response_type, 'code'); | ||
assert.equal(parsed.query.response_mode, undefined); | ||
assert.equal(parsed.query.redirect_uri, 'https://myapp.com/callback'); | ||
assert.equal(parsed.query.redirect_uri, 'https://example.org/callback'); | ||
assert.property(parsed.query, 'nonce'); | ||
@@ -164,5 +163,5 @@ assert.property(parsed.query, 'state'); | ||
router = router = expressOpenid.auth({ | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
authorizationParams: { | ||
@@ -183,9 +182,9 @@ response_mode: undefined, | ||
assert.equal(parsed.hostname, 'flosser.auth0.com'); | ||
assert.equal(parsed.hostname, 'test.auth0.com'); | ||
assert.equal(parsed.pathname, '/authorize'); | ||
assert.equal(parsed.query.client_id, '123'); | ||
assert.equal(parsed.query.client_id, '__test_client_id__'); | ||
assert.equal(parsed.query.scope, 'openid profile email'); | ||
assert.equal(parsed.query.response_type, 'id_token'); | ||
assert.equal(parsed.query.response_mode, undefined); | ||
assert.equal(parsed.query.redirect_uri, 'https://myapp.com/callback'); | ||
assert.equal(parsed.query.redirect_uri, 'https://example.org/callback'); | ||
assert.property(parsed.query, 'nonce'); | ||
@@ -196,17 +195,48 @@ assert.property(parsed.query, 'state'); | ||
it('should contain the two callbacks route', function() { | ||
assert.ok(router.stack.some(filterRoute('POST', '/callback'))); | ||
assert.ok(router.stack.some(filterRoute('GET', '/callback'))); | ||
}); | ||
it('should return an html on GET /callback', async function() { | ||
const cookieJar = request.jar(); | ||
const res = await request.get('/callback', { cookieJar, baseUrl, followRedirect: false }); | ||
assert.equal(res.statusCode, 200); | ||
assert.equal(res.headers['content-type'], 'text/html; charset=utf-8'); | ||
const expectedBody = fs.readFileSync(`${__dirname}/../views/repost.html`, 'utf-8'); | ||
assert.equal(res.body, expectedBody); | ||
}); | ||
}); | ||
describe('custom path values', () => { | ||
let baseUrl, router; | ||
before(async function() { | ||
router = expressOpenid.auth({ | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
redirectUriPath: '/custom-callback', | ||
loginPath: '/custom-login', | ||
logoutPath: '/custom-logout', | ||
}); | ||
baseUrl = await server.create(router); | ||
}); | ||
it('should contain the custom login route', function() { | ||
assert.ok(router.stack.some(filterRoute('GET', '/custom-login'))); | ||
}); | ||
it('should contain the custom logout route', function() { | ||
assert.ok(router.stack.some(filterRoute('GET', '/custom-logout'))); | ||
}); | ||
it('should contain the custom callback route', function() { | ||
assert.ok(router.stack.some(filterRoute('POST', '/custom-callback'))); | ||
}); | ||
it('should redirect to the authorize url properly on /login', async function() { | ||
const jar = request.jar(); | ||
const res = await request.get('/custom-login', { jar, baseUrl, followRedirect: false }); | ||
assert.equal(res.statusCode, 302); | ||
const parsed = url.parse(res.headers.location, true); | ||
assert.equal(parsed.hostname, 'test.auth0.com'); | ||
assert.equal(parsed.pathname, '/authorize'); | ||
assert.equal(parsed.query.redirect_uri, 'https://example.org/custom-callback'); | ||
}); | ||
}); | ||
}); |
@@ -11,3 +11,3 @@ const assert = require('chai').assert; | ||
const cert = require('./fixture/cert'); | ||
const clientID = 'foobar'; | ||
const clientID = '__test_client_id__'; | ||
@@ -18,4 +18,4 @@ function testCase(params) { | ||
clientID: clientID, | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
required: false | ||
@@ -66,4 +66,4 @@ }); | ||
session: { | ||
nonce: '123', | ||
state: '123' | ||
nonce: '__test_nonce__', | ||
state: '__test_state__' | ||
}, | ||
@@ -84,9 +84,7 @@ body: true, | ||
session: { | ||
nonce: '123', | ||
state: '123' | ||
nonce: '__test_nonce__', | ||
state: '__valid_state__' | ||
}, | ||
body: { | ||
nonce: '123', | ||
state: '456', | ||
id_token: 'sioua' | ||
state: '__invalid_state__' | ||
}, | ||
@@ -106,9 +104,8 @@ assertions() { | ||
session: { | ||
nonce: '123', | ||
state: '123' | ||
nonce: '__test_nonce__', | ||
state: '__test_state__' | ||
}, | ||
body: { | ||
nonce: '123', | ||
state: '123', | ||
id_token: 'sioua' | ||
state: '__test_state__', | ||
id_token: '__invalid_token__' | ||
}, | ||
@@ -128,9 +125,8 @@ assertions() { | ||
session: { | ||
nonce: '123', | ||
state: '123' | ||
nonce: '__test_nonce__', | ||
state: '__test_state__' | ||
}, | ||
body: { | ||
nonce: '123', | ||
state: '123', | ||
id_token: jwt.sign({ foo: '123'}, 'f00') | ||
state: '__test_state__', | ||
id_token: jwt.sign({sub: '__test_sub__'}, '__invalid_alg__') | ||
}, | ||
@@ -150,9 +146,8 @@ assertions() { | ||
session: { | ||
nonce: '123', | ||
state: '123' | ||
nonce: '__test_nonce__', | ||
state: '__test_state__' | ||
}, | ||
body: { | ||
nonce: '123', | ||
state: '123', | ||
id_token: jwt.sign({ foo: '123'}, cert.key, { algorithm: 'RS256' }) | ||
state: '__test_state__', | ||
id_token: jwt.sign({sub: '__test_sub__'}, cert.key, { algorithm: 'RS256' }) | ||
}, | ||
@@ -172,20 +167,19 @@ assertions() { | ||
session: { | ||
state: '123', | ||
nonce: 'abcdefg', | ||
returnTo: '/foobar' | ||
state: '__test_state__', | ||
nonce: '__test_nonce__', | ||
returnTo: '/return-to' | ||
}, | ||
body: { | ||
nonce: '123', | ||
state: '123', | ||
state: '__test_state__', | ||
id_token: jwt.sign({ | ||
'nickname': 'jjjj', | ||
'name': 'Jeranio', | ||
'email': 'jjjj@example.com', | ||
'nickname': '__test_nickname__', | ||
'name': '__test_name__', | ||
'email': '__test_email__', | ||
'email_verified': true, | ||
'iss': 'https://flosser.auth0.com/', | ||
'sub': 'xasdas', | ||
'iss': 'https://test.auth0.com/', | ||
'sub': '__test_sub__', | ||
'aud': clientID, | ||
'iat': Math.round(Date.now() / 1000), | ||
'exp': Math.round(Date.now() / 1000) + 60000, | ||
'nonce': 'abcdefg' | ||
'nonce': '__test_nonce__' | ||
}, cert.key, { algorithm: 'RS256', header: { kid: cert.kid } }) | ||
@@ -199,3 +193,3 @@ }, | ||
it('should redirect to the intended url', function() { | ||
assert.equal(this.response.headers['location'], '/foobar'); | ||
assert.equal(this.response.headers['location'], '/return-to'); | ||
}); | ||
@@ -213,3 +207,3 @@ | ||
}); | ||
assert.equal(res.body.nickname, 'jjjj'); | ||
assert.equal(res.body.nickname, '__test_nickname__'); | ||
}); | ||
@@ -216,0 +210,0 @@ } |
@@ -7,5 +7,5 @@ const { assert } = require('chai'); | ||
const config = getConfig({ | ||
clientID: '123', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
baseURL: 'https://jjj.com', | ||
clientID: '__test_client_id__', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
baseURL: 'https://example.org', | ||
}); | ||
@@ -32,6 +32,6 @@ | ||
const config = getConfig({ | ||
clientID: '123', | ||
clientSecret: '123', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
baseURL: 'https://jjj.com', | ||
clientID: '__test_client_id__', | ||
clientSecret: '__test_client_secret__', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
baseURL: 'https://example.org', | ||
authorizationParams: { | ||
@@ -57,5 +57,5 @@ response_type: 'code' | ||
const config = getConfig({ | ||
clientID: '123', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
baseURL: 'https://jjj.com', | ||
clientID: '__test_client_id__', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
baseURL: 'https://example.org', | ||
auth0Logout: true | ||
@@ -72,5 +72,5 @@ }); | ||
const config = getConfig({ | ||
clientID: '123', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
baseURL: 'https://jjj.com', | ||
clientID: '__test_client_id__', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
baseURL: 'https://example.org', | ||
}); | ||
@@ -86,5 +86,5 @@ | ||
const config = getConfig({ | ||
clientID: '123', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
baseURL: 'https://jjj.com', | ||
clientID: '__test_client_id__', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
baseURL: 'https://example.org', | ||
idpLogout: true | ||
@@ -99,2 +99,45 @@ }); | ||
describe('default auth paths', function() { | ||
const config = getConfig({ | ||
clientID: '__test_client_id__', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
baseURL: 'https://example.org', | ||
}); | ||
it('should set the default callback path', function() { | ||
assert.equal(config.redirectUriPath, '/callback'); | ||
}); | ||
it('should set the default login path', function() { | ||
assert.equal(config.loginPath, '/login'); | ||
}); | ||
it('should set the default logout path', function() { | ||
assert.equal(config.logoutPath, '/logout'); | ||
}); | ||
}); | ||
describe('custom auth paths', function() { | ||
const config = getConfig({ | ||
clientID: '__test_client_id__', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
baseURL: 'https://example.org', | ||
redirectUriPath: '/custom-callback', | ||
loginPath: '/custom-login', | ||
logoutPath: '/custom-logout', | ||
}); | ||
it('should accept the custom callback path', function() { | ||
assert.equal(config.redirectUriPath, '/custom-callback'); | ||
}); | ||
it('should accept the login path', function() { | ||
assert.equal(config.loginPath, '/custom-login'); | ||
}); | ||
it('should accept the logout path', function() { | ||
assert.equal(config.logoutPath, '/custom-logout'); | ||
}); | ||
}); | ||
}); |
@@ -23,5 +23,5 @@ const assert = require('chai').assert; | ||
router = expressOpenid.auth({ | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
required: false, | ||
@@ -42,3 +42,3 @@ redirectUriPath: '/auth-finish' | ||
const parsed = url.parse(res.headers.location, true); | ||
assert.equal(parsed.query.redirect_uri, 'https://myapp.com/auth-finish'); | ||
assert.equal(parsed.query.redirect_uri, 'https://example.org/auth-finish'); | ||
}); | ||
@@ -45,0 +45,0 @@ |
@@ -7,3 +7,3 @@ const selfsigned = require('selfsigned'); | ||
name: 'commonName', | ||
value: 'flosser.auth0.com' | ||
value: 'test.auth0.com' | ||
} | ||
@@ -10,0 +10,0 @@ ]; |
@@ -10,4 +10,4 @@ const express = require('express'); | ||
app.use(cookieSession({ | ||
name: 'tests', | ||
secret: 'blabla', | ||
name: '__test_name__', | ||
secret: '__test_secret__', | ||
})); | ||
@@ -14,0 +14,0 @@ |
{ | ||
"issuer": "https://flosser.auth0.com/", | ||
"authorization_endpoint": "https://flosser.auth0.com/authorize", | ||
"token_endpoint": "https://flosser.auth0.com/oauth/token", | ||
"userinfo_endpoint": "https://flosser.auth0.com/userinfo", | ||
"mfa_challenge_endpoint": "https://flosser.auth0.com/mfa/challenge", | ||
"jwks_uri": "https://flosser.auth0.com/.well-known/jwks.json", | ||
"registration_endpoint": "https://flosser.auth0.com/oidc/register", | ||
"revocation_endpoint": "https://flosser.auth0.com/oauth/revoke", | ||
"issuer": "https://test.auth0.com/", | ||
"authorization_endpoint": "https://test.auth0.com/authorize", | ||
"token_endpoint": "https://test.auth0.com/oauth/token", | ||
"userinfo_endpoint": "https://test.auth0.com/userinfo", | ||
"mfa_challenge_endpoint": "https://test.auth0.com/mfa/challenge", | ||
"jwks_uri": "https://test.auth0.com/.well-known/jwks.json", | ||
"registration_endpoint": "https://test.auth0.com/oidc/register", | ||
"revocation_endpoint": "https://test.auth0.com/oauth/revoke", | ||
"introspection_endpoint": "https://test.auth0.com/introspection", | ||
"scopes_supported": ["openid", "profile", "offline_access", "name", "given_name", "family_name", "nickname", "email", "email_verified", "picture", "created_at", "identities", "phone", "address"], | ||
@@ -11,0 +12,0 @@ "response_types_supported": ["code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token", "none"], |
@@ -8,5 +8,5 @@ const { assert } = require('chai'); | ||
expressOpenid.auth({ | ||
baseURL: 'http://localhost', | ||
issuerBaseURL: '123 r423.json xxx', | ||
clientID: '123ewasda' | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: '__invalid_url__', | ||
clientID: '__test_client_id__' | ||
}); | ||
@@ -19,5 +19,5 @@ }, '"issuerBaseURL" must be a valid uri'); | ||
expressOpenid.auth({ | ||
baseURL: 'xasxasa sads', | ||
issuerBaseURL: 'http://foobar.com', | ||
clientID: '123ewasda' | ||
baseURL: '__invalid_url__', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
clientID: '__test_client_id__' | ||
}); | ||
@@ -30,4 +30,4 @@ }, '"baseURL" must be a valid uri'); | ||
expressOpenid.auth({ | ||
baseURL: 'http://foobar.com', | ||
issuerBaseURL: 'http://foobar.com', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
}); | ||
@@ -40,4 +40,4 @@ }, '"clientID" is required'); | ||
expressOpenid.auth({ | ||
issuerBaseURL: 'http://foobar.com', | ||
clientID: 'asdas', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
clientID: '__test_client_id__', | ||
}); | ||
@@ -50,5 +50,5 @@ }, '"baseURL" is required'); | ||
expressOpenid.auth({ | ||
issuerBaseURL: 'http://foobar.auth0.com', | ||
baseURL: 'http://foobar.com', | ||
clientID: 'asdas', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
baseURL: 'https://example.org', | ||
clientID: '__test_client_id__', | ||
authorizationParams: { | ||
@@ -60,2 +60,13 @@ response_type: 'code id_token' | ||
}); | ||
it('should fail when client secret is not provided and using an HS256 ID token algorithm', function() { | ||
assert.throws(() => { | ||
expressOpenid.auth({ | ||
issuerBaseURL: 'http://foobar.auth0.com', | ||
baseURL: 'http://foobar.com', | ||
clientID: 'asdas', | ||
idTokenAlg: 'HS256' | ||
}); | ||
}, '"clientSecret" is required for ID tokens with HS algorithms'); | ||
}); | ||
}); |
@@ -12,7 +12,7 @@ const assert = require('chai').assert; | ||
const router = expressOpenid.auth({ | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
authorizationParams: { | ||
response_mode: 'ffff', | ||
response_mode: '__invalid_response_mode__', | ||
response_type: 'id_token' | ||
@@ -30,4 +30,4 @@ } | ||
assert.equal(res.statusCode, 500); | ||
assert.include(res.body.err.message, 'The issuer doesn\'t support the response_mode ffff'); | ||
assert.include(res.body.err.message, 'Response mode "__invalid_response_mode__" is not supported by the issuer.'); | ||
}); | ||
}); |
@@ -12,7 +12,7 @@ const assert = require('chai').assert; | ||
const router = expressOpenid.auth({ | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
authorizationParams: { | ||
response_type: 'bufanda' | ||
response_type: '__invalid_response_type__' | ||
} | ||
@@ -29,4 +29,4 @@ }); | ||
assert.equal(res.statusCode, 500); | ||
assert.include(res.body.err.message, 'The issuer doesn\'t support the response_type bufanda'); | ||
assert.include(res.body.err.message, 'Response type "__invalid_response_type__" is not supported by the issuer.'); | ||
}); | ||
}); |
@@ -21,5 +21,5 @@ const { assert } = require('chai'); | ||
idpLogout: false, | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
required: false | ||
@@ -47,3 +47,3 @@ }); | ||
assert.equal(logoutResponse.statusCode, 302); | ||
assert.equal(logoutResponse.headers.location, 'https://myapp.com'); | ||
assert.equal(logoutResponse.headers.location, 'https://example.org'); | ||
}); | ||
@@ -61,5 +61,5 @@ }); | ||
idpLogout: true, | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
required: false | ||
@@ -90,4 +90,4 @@ }); | ||
protocol: 'https:', | ||
hostname: 'flosser.auth0.com', | ||
query: { returnTo: 'https://myapp.com', client_id: '123' }, | ||
hostname: 'test.auth0.com', | ||
query: { returnTo: 'https://example.org', client_id: '__test_client_id__' }, | ||
pathname: '/v2/logout', | ||
@@ -94,0 +94,0 @@ }); |
@@ -17,5 +17,5 @@ const { assert } = require('chai'); | ||
const router = auth({ | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
required: false | ||
@@ -31,3 +31,3 @@ }); | ||
it('should contain a location header to the issuer', function() { | ||
assert.include(response.headers.location, 'https://flosser.auth0.com'); | ||
assert.include(response.headers.location, 'https://test.auth0.com'); | ||
}); | ||
@@ -57,5 +57,5 @@ }); | ||
const router = auth({ | ||
clientID: '123', | ||
baseURL: 'https://myapp.com', | ||
issuerBaseURL: 'https://flosser.auth0.com', | ||
clientID: '__test_client_id__', | ||
baseURL: 'https://example.org', | ||
issuerBaseURL: 'https://test.auth0.com', | ||
required: false, | ||
@@ -62,0 +62,0 @@ errorOnRequiredAuth: true |
@@ -6,3 +6,3 @@ const nock = require('nock'); | ||
before(function() { | ||
nock('https://flosser.auth0.com', { allowUnmocked: true }) | ||
nock('https://test.auth0.com', { allowUnmocked: true }) | ||
.persist() | ||
@@ -12,3 +12,3 @@ .get('/.well-known/openid-configuration') | ||
nock('https://flosser.auth0.com', { allowUnmocked: true }) | ||
nock('https://test.auth0.com', { allowUnmocked: true }) | ||
.persist() | ||
@@ -15,0 +15,0 @@ .get('/.well-known/jwks.json') |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
74901
36
1507
1
15
123
Updatedopenid-client@^3.7.3