-
Notifications
You must be signed in to change notification settings - Fork 9.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(auth): running Lighthouse on authenticated pages (#9628)
- Loading branch information
1 parent
364ca59
commit e7a9b5f
Showing
11 changed files
with
423 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Running Lighthouse on Authenticated Pages | ||
|
||
Default runs of Lighthouse load a page as a "new user", with no previous session or storage data. This means that pages requiring authenticated access do not work without additional setup. You have a few options for running Lighthouse on pages behind a login: | ||
|
||
## Option 1: Script the login with Puppeteer | ||
|
||
[Puppeteer](https://pptr.dev) is the most flexible approach for running Lighthouse on pages requiring authentication. | ||
|
||
See [a working demo at /docs/recipes/auth](./recipes/auth). | ||
|
||
## Option 2: Leverage logged-in state with Chrome DevTools | ||
|
||
The Audits panel in Chrome DevTools will never clear your cookies, so you can log in to the target site and then run Lighthouse. If `localStorage` or `indexedDB` is important for your authentication purposes, be sure to uncheck `Clear storage`. | ||
|
||
## Option 3: Pass custom request headers with Lighthouse CLI | ||
|
||
CLI: | ||
```sh | ||
lighthouse http://www.example.com --view --extra-headers="{\"Authorization\":\"...\"}" | ||
``` | ||
|
||
Node: | ||
```js | ||
const result = await lighthouse('http://www.example.com', { | ||
extraHeaders: { | ||
Authorization: '...', | ||
}, | ||
}); | ||
``` | ||
|
||
You could also set the `Cookie` header, but beware: it will [override any other Cookies you expect to be there](https://github.com/GoogleChrome/lighthouse/pull/9170). A workaround is to use Puppeteer's [`page.setCookie`](https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#pagesetcookiecookies). | ||
|
||
## Option 4: Open a debug instance of Chrome and manually log in | ||
|
||
1. Globally install lighthouse: `npm i -g lighthouse` or `yarn global add lighthouse`. `chrome-debug` is now in your PATH. This binary launches a standalone Chrome instance with an open debugging port. | ||
1. Run chrome-debug. This logs the debugging port of your Chrome instance. | ||
1. Navigate to your site and log in. | ||
1. In a separate terminal, run `lighthouse http://mysite.com --port port-number`, using the port number from chrome-debug. | ||
|
||
## Option 5: Reuse a prepared Chrome User Profile | ||
|
||
This option is currently under development. Track or join the discussion here: [#8957](https://github.com/GoogleChrome/lighthouse/issues/8957). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
/** | ||
* @license Copyright 2019 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
'use strict'; | ||
|
||
module.exports = { | ||
extends: '../../../.eslintrc.js', | ||
env: { | ||
jest: true, | ||
}, | ||
rules: { | ||
'new-cap': 0, | ||
'no-console': 0, | ||
'no-unused-vars': 0, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
# Running Lighthouse on Authenticated Pages with Puppeteer | ||
|
||
If you just want to view the code for using Lighthouse with Puppeteer, see [example-lh-auth.js](./example-lh-auth.js). | ||
|
||
## The Example Site | ||
|
||
There are two pages on the site: | ||
|
||
1. `/` - the homepage | ||
2. `/dashboard` | ||
|
||
The homepage shows the login form, but only to users that are not signed in. | ||
|
||
The dashboard shows a secret to users that are logged in, but shows an error to users that are not. | ||
|
||
The server responds with different HTML for each of these pages and session states. | ||
|
||
(Optional) To run the server: | ||
```sh | ||
# be in root lighthouse directory | ||
yarn # install global project deps | ||
cd docs/auth | ||
yarn # install deps related to just this recipe | ||
yarn start # start the server on http://localhost:8000 | ||
``` | ||
|
||
Now that the server is started, let's login with Puppeteer and then run Lighthouse: | ||
```sh | ||
node example-lh-auth.js | ||
``` | ||
What does this do? Read on.... | ||
|
||
## Process | ||
|
||
Puppeteer - a browser automation tool - can be used to programatically setup a session. | ||
|
||
1. Launch a new browser. | ||
1. Navigate to the login page. | ||
1. Fill and submit the login form. | ||
1. Run Lighthouse using the same browser. | ||
|
||
First, launch Chrome: | ||
```js | ||
// This port will be used by Lighthouse later. The specific port is arbitrary. | ||
const PORT = 8041; | ||
const browser = await puppeteer.launch({ | ||
args: [`--remote-debugging-port=${PORT}`], | ||
// Optional, if you want to see the tests in action. | ||
headless: false, | ||
slowMo: 50, | ||
}); | ||
``` | ||
|
||
Navigate to the login form: | ||
```js | ||
const page = await browser.newPage(); | ||
await page.goto('http://localhost:8000'); | ||
``` | ||
|
||
Given a login form like this: | ||
```html | ||
<form action="/login" method="post"> | ||
<label> | ||
Email: | ||
<input type="email" name="email"> | ||
</label> | ||
<label> | ||
Password: | ||
<input type="password" name="password"> | ||
</label> | ||
<input type="submit"> | ||
</form> | ||
``` | ||
|
||
Direct Puppeteer to fill and submit it: | ||
```js | ||
const emailInput = await page.$('input[type="email"]'); | ||
await emailInput.type('admin@example.com'); | ||
const passwordInput = await page.$('input[type="password"]'); | ||
await passwordInput.type('password'); | ||
await Promise.all([ | ||
page.$eval('.login-form', form => form.submit()), | ||
page.waitForNavigation(), | ||
]); | ||
``` | ||
|
||
At this point, the session that Puppeteer is managing is now logged in. | ||
|
||
Close the page used to log in: | ||
```js | ||
await page.close(); | ||
// The page has been closed, but the browser still has the relevant session. | ||
``` | ||
|
||
Now run Lighthouse, using the same port as before: | ||
```js | ||
// The local server is running on port 8000. | ||
const url = 'http://localhost:8000/dashboard'; | ||
// Direct Lighthouse to use the same port. | ||
const result = await lighthouse(url, { port: PORT }); | ||
const lhr = result.lhr; | ||
|
||
// Direct Puppeteer to close the browser - we're done with it. | ||
await browser.close(); | ||
``` | ||
|
||
All of the above is done in the example script. To run: | ||
```sh | ||
# make sure server is running (see beginning of recipe) ... | ||
node example-lh-auth.js # login via puppeteer and run lighthouse | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* @license Copyright 2019 Google Inc. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
'use strict'; | ||
|
||
/** | ||
* @fileoverview Example script for running Lighthouse on an authenticated page. | ||
* See docs/recipes/auth/README.md for more. | ||
*/ | ||
|
||
const puppeteer = require('puppeteer'); | ||
const lighthouse = require('lighthouse'); | ||
|
||
// This port will be used by Lighthouse later. The specific port is arbitrary. | ||
const PORT = 8041; | ||
|
||
/** | ||
* @param {import('puppeteer').Browser} browser | ||
*/ | ||
async function login(browser) { | ||
const page = await browser.newPage(); | ||
await page.goto('http://localhost:8000'); | ||
await page.waitForSelector('input[type="email"]', {visible: true}); | ||
|
||
// Fill in and submit login form. | ||
const emailInput = await page.$('input[type="email"]'); | ||
await emailInput.type('admin@example.com'); | ||
const passwordInput = await page.$('input[type="password"]'); | ||
await passwordInput.type('password'); | ||
await Promise.all([ | ||
page.$eval('.login-form', form => form.submit()), | ||
page.waitForNavigation(), | ||
]); | ||
|
||
await page.close(); | ||
} | ||
|
||
async function main() { | ||
// Direct Puppeteer to open Chrome with a specific debugging port. | ||
const browser = await puppeteer.launch({ | ||
args: [`--remote-debugging-port=${PORT}`], | ||
// Optional, if you want to see the tests in action. | ||
headless: false, | ||
slowMo: 50, | ||
}); | ||
|
||
// Setup the browser session to be logged into our site. | ||
await login(browser); | ||
|
||
// The local server is running on port 8000. | ||
const url = 'http://localhost:8000/dashboard'; | ||
// Direct Lighthouse to use the same port. | ||
const result = await lighthouse(url, {port: PORT}); | ||
// Direct Puppeteer to close the browser as we're done with it. | ||
await browser.close(); | ||
|
||
// Output the result. | ||
console.log(JSON.stringify(result.lhr, null, 2)); | ||
} | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"scripts": { | ||
"start": "node server/server.js" | ||
}, | ||
"dependencies": { | ||
"express": "^4.17.1", | ||
"express-session": "^1.16.2", | ||
"lighthouse": "file:../../..", | ||
"morgan": "^1.9.1" | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
docs/recipes/auth/server/public/dashboard-unauthenticated.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<!-- | ||
Copyright 2019 Google Inc. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
--> | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Dashboard - Unauthenticated</title> | ||
</head> | ||
<body> | ||
you need to be logged in. | ||
<style> | ||
body { | ||
background-color: #CD5C5C; | ||
} | ||
</style> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<!-- | ||
Copyright 2019 Google Inc. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
--> | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Dashboard</title> | ||
</head> | ||
<body> | ||
<h1>Dashboard</h1> | ||
<div> | ||
secrets here | ||
</div> | ||
<a href="/logout">logout</a> | ||
<style> | ||
body { | ||
background-color: green; | ||
} | ||
</style> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<!-- | ||
Copyright 2019 Google Inc. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
--> | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Home - Login</title> | ||
</head> | ||
<body> | ||
<h1>Plz login</h1> | ||
<form class="login-form" action="/login" method="post"> | ||
<label> | ||
Email: | ||
<input type="email" name="email"> | ||
</label> | ||
<label> | ||
Password: | ||
<input type="password" name="password"> | ||
</label> | ||
<input type="submit"> | ||
</form> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!-- | ||
Copyright 2019 Google Inc. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
--> | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Home - Logged In</title> | ||
</head> | ||
<body> | ||
<h1>Welcome home!</h1> | ||
<span>You are logged in. Go to <a href="/dashboard">the dashboard</a>.</span> | ||
</body> | ||
</html> |
Oops, something went wrong.