# How to screenshot a page behind a login, safely

> Four ways to screenshot a page that needs a login: session cookie, bearer token, Basic auth or a signed link. What each one risks, and the safest pattern.

Guide by Serghei Pogor, founder of CurlShot (https://curlshot.com/about/serghei-pogor). Published 26 October 2026. Page for people: https://curlshot.com/blog/screenshot-pages-behind-login

To screenshot a page behind a login, do not automate the login form. Sign in once yourself, then send proof of that sign-in with the capture request. There are 4 ways to do it: a session cookie, a bearer token in the Authorization header, HTTP Basic credentials, or a signed link that expires. Use the weakest one that opens the page, from a dedicated read-only account, sent from your server over HTTPS, and only for pages you are authorised to open.

## Key facts

- A session cookie is as powerful as the login it came from: OWASP calls a session ID "temporarily equivalent to the strongest authentication method used by the application".
- A signed, expiring link is the safest of the 4 keys, because it opens one page, read-only, until a set time. It is also the only one that travels in the address, so it must expire quickly.
- Basic authentication sends the password itself with every request. Base64 is reversible, and RFC 7617 says the scheme is not secure without TLS.
- A secret in a query string is written to web logs, browser history and Referer headers, and HTTPS does not prevent that. Send secrets in a POST body or a header.
- An expired session does not fail: it returns a clean screenshot of the login page. Wait for an element that only exists when signed in.
- CurlShot takes cookies, an authorization value and headers, sends credentials only to the origin of the page, masks them in the stored record, and refuses private network addresses.

## Four keys, one door

A login page is a door. A capture tool should not pick the lock by typing a password into the form. It should arrive holding a key: proof that someone authorised already signed in. There are 4 such keys. This guide is for pages you are authorised to open: your own dashboards, accounts and staging sites.

### Key 1: Session cookie

What a browser sends after you sign in. Risk: high (3 of 4, our rating, for the reasons below).

```http
GET /reports/monthly HTTP/1.1
Host: example.com
Cookie: session=PASTE_SESSION_COOKIE_VALUE
```

- `GET /reports/monthly HTTP/1.1`: Request line: the page you want
- `Host: example.com`: The site the cookie belongs to
- `Cookie: session=PASTE_SESSION_COOKIE_VALUE`: The secret: proof that someone already signed in (this line carries the secret)

What the server checks: The site looks the value up in its session store. A live session opens the page as that user. An unknown or expired one gets the login page, usually through a redirect.

- How long does it live? Until the site ends the session or the user logs out. OWASP suggests idle timeouts of 2 to 5 minutes for high-value applications and 15 to 30 minutes for low-risk ones, but each site decides.
- What can it do if it leaks? Everything the account can do. OWASP calls a session ID "temporarily equivalent to the strongest authentication method used by the application".
- Can it be limited to one page? No. A session covers the whole account. The only limit is the account itself, which is why it should be a dedicated read-only one.

Use it when: The site has an ordinary login form, single sign-on or two-factor authentication, and offers no tokens or share links. You sign in yourself once and hand over the finished session.

Avoid it when: The only account you have is your own or an administrator account, or the site ties a session to one device or IP address.

### Key 2: Bearer token

A token in the `Authorization` header. Risk: medium (2 of 4, our rating, for the reasons below).

```http
GET /reports/monthly HTTP/1.1
Host: example.com
Authorization: Bearer PASTE_READ_ONLY_TOKEN
```

- `GET /reports/monthly HTTP/1.1`: Request line: the page you want
- `Host: example.com`: The site that issued the token
- `Authorization: Bearer PASTE_READ_ONLY_TOKEN`: The secret: whoever holds it may use it (this line carries the secret)

What the server checks: The site checks that the token is genuine, has not expired and is allowed to read this page. A bad token gets `401`. A good token without the right gets `403`.

- How long does it live? As long as its issuer says. RFC 6750 recommends short-lived bearer tokens, "one hour or less".
- What can it do if it leaks? Whatever the token was granted, for anyone who has it: RFC 6750 defines a bearer token as one that "any party in possession of" can use.
- Can it be limited to one page? Sometimes. Many issuers let you create a read-only token or one with a narrow scope. Few can limit it to a single page.

Use it when: The site or your own application issues tokens for automation, such as a service token or a read-only access token. This is the key made for machines.

Avoid it when: The only token available has write or administrator rights, or the page calls a second host that also needs the token.

### Key 3: HTTP Basic authentication

A name and password, base64-encoded. Risk: highest (4 of 4, our rating, for the reasons below).

```http
GET /staging HTTP/1.1
Host: example.com
Authorization: Basic dXNlcjpwYXNz
```

- `GET /staging HTTP/1.1`: Request line: the page you want
- `Host: example.com`: The site behind the password box
- `Authorization: Basic dXNlcjpwYXNz`: The secret: user:pass in base64, which anyone can decode (this line carries the secret)

What the server checks: The site decodes the value and compares the name and password. A wrong pair gets `401` and a `WWW-Authenticate` header, which is what makes a browser show its grey password box.

- How long does it live? Until someone changes the password. Nothing expires on its own.
- What can it do if it leaks? It is the password itself, sent with every request. Base64 is an encoding, not encryption: MDN warns that Basic authentication "offers no cryptographic security", and RFC 7617 says it is not secure without TLS.
- Can it be limited to one page? No. The pair opens everything behind that password box.

Use it when: A staging or preview site sits behind a shared password that protects nothing else, and the address is `https://`.

Avoid it when: The password is also used anywhere else, belongs to a person, or the site is served over plain `http://`.

### Key 4: Signed or expiring link

A link your application makes for one page. Risk: lowest (1 of 4, our rating, for the reasons below).

```http
GET /share/report-42?expires=1798761600&signature=3f9a...c21 HTTP/1.1
Host: example.com
(no credential header)
```

- `GET /share/report-42?expires=1798761600&signature=3f9a...c21 HTTP/1.1`: The secret is the address itself: one page, until a set time (this line carries the secret)
- `Host: example.com`: The application that made the link
- `(no credential header)`: Nothing else is sent

What the server checks: The application recomputes the signature from the path and the expiry with a key that never leaves the server, then checks the clock. A changed or expired link gets `403`.

- How long does it live? Until the time written into it. Amazon S3 presigned URLs, a well-known example, can be set from 1 minute to 12 hours in the console and up to 7 days through the SDKs.
- What can it do if it leaks? Open that one page, read-only, until it expires. It is still a secret in a URL, and URLs are written to logs, so the expiry has to be short.
- Can it be limited to one page? Yes. That is the point of it: the signature covers one path.

Use it when: You own the application and can add a route that renders one report for a signed, expiring link. This is the best key when you can build it.

Avoid it when: The link never expires, or it opens more than the one page it was made for.

## Session cookie, bearer token, Basic auth or signed link: comparison

| Key | What you send | How long it lives | Blast radius if leaked | One page only? | Works with SSO or 2FA? | Effort |
| --- | --- | --- | --- | --- | --- | --- |
| 1. Session cookie | `Cookie: session=...` | Until the session expires or the user logs out. The site decides: OWASP suggests 2 to 30 minutes idle, 4 to 8 hours in total for an office application. | The whole account, with every right it has | No. Scope it by using a read-only account. | Yes. You complete the sign-in and the second factor yourself; the cookie carries the finished session. | Low: copy one value from the browser. Repeat when it expires. |
| 2. Bearer token | `Authorization: Bearer ...` | Set by the issuer. RFC 6750 recommends one hour or less. | What the token was granted, no more | Partly: read-only or narrow scopes where the issuer offers them. | Yes, when the site issues tokens. No login step happens at capture time. | Low once a token exists. Higher when it must be refreshed every hour. |
| 3. HTTP Basic authentication | `Authorization: Basic ...` | Until the password is changed | Everything behind that password, and every other place the password is reused | No | No. Basic authentication is a name and a password only. | Lowest: one value, no expiry to handle. |
| 4. Signed or expiring link | A URL with `expires` and `signature` in it | The expiry written into the link, for example minutes | One page, read-only, until it expires | Yes, by design | Yes. Your server makes the link after its own checks; nobody signs in at capture time. | Highest at first: your application has to make and check the links. |

Typing a name and password into the login form with a script is not on this list. It does not get past single sign-on, a CAPTCHA or two-factor authentication, those checks exist to stop automated sign-ins, and it puts a real password into a script. Do not attempt it. Sign in yourself and hand over the result.

## Where does the secret travel?

A secret passes through 5 places on the way to a screenshot. "Written down" marks the places where it is likely to be recorded.

| Hop | Session cookie | Bearer token | HTTP Basic authentication | Signed or expiring link |
| --- | --- | --- | --- | --- |
| 1. Your server | Stored, by you. Keep it in a secret store or an environment variable, readable by the capture job only. Not in the code, not in the repository. | Stored, by you. Keep it in a secret store or an environment variable, readable by the capture job only. Not in the code, not in the repository. | Stored, by you. Keep it in a secret store or an environment variable, readable by the capture job only. Not in the code, not in the repository. | Stored, by you. Only the signing key rests here, and it never leaves. Your server makes a fresh link for each capture. |
| 2. The request | Passes through. Send it in the JSON body of a `POST` over HTTPS. A request body is not part of the address, so it stays out of access logs, browser history and `Referer` headers. | Passes through. Send it in the JSON body of a `POST` over HTTPS. A request body is not part of the address, so it stays out of access logs, browser history and `Referer` headers. | Passes through. Send it in the JSON body of a `POST` over HTTPS. A request body is not part of the address, so it stays out of access logs, browser history and `Referer` headers. | Passes through. The link is the `url` of the request. Send it in a `POST` body over HTTPS like any other secret. |
| 3. Capture service | Passes through. The service needs the real value to set the cookie, so it holds it while the job runs. What it keeps afterwards is the question to ask: its stored record should mask the value. | Passes through. The service holds the token while the job runs. OWASP lists access tokens among the data that should not be recorded directly in logs, so the stored record should mask it. | Passes through. The service holds the encoded pair while the job runs. Masking matters most here: base64 is reversible, so a logged value is a logged password. | Written down. A capture service records which address it rendered, so the link can be written into its history, and into its web logs before that. Some services mask the signature in the stored record; do not count on it. This is why the link must expire soon after the capture. |
| 4. Target site | Passes through. The browser sends the cookie only to hosts that match its `Domain` and `Path`, as any browser does. Other hosts the page loads from never see it. | Passes through. The header should reach the site in the address and nobody else. Browsers strip `Authorization` from cross-origin redirects; a capture service must do the same for every other host the page loads from. | Passes through. Over `https://` the pair is encrypted in transit. Over `http://` it crosses the network in clear text, which RFC 7617 names as the main flaw of the scheme. | Written down. The secret is in the request line, and web servers log request lines. OWASP notes that HTTPS does not change this. By the time anyone reads the log, the link should be dead. |
| 5. The screenshot | No secret here. The image holds no credential, but it shows everything the account can see. Store it like the data it shows. | No secret here. The image holds no credential, but it shows everything the account can see. Store it like the data it shows. | No secret here. The image holds no credential, but it shows everything the account can see. Store it like the data it shows. | No secret here. The image holds no credential, but it shows everything the account can see. Store it like the data it shows. |

## The safest way to screenshot a page behind a login

1. **Pick the weakest key that opens the page.** Prefer an expiring link, then a read-only token, then the session cookie of a dedicated account. Use Basic authentication only for a shared staging password. Why: The less a secret can do and the sooner it dies, the less a leak costs.
2. **Make an account or a link only for captures.** Create a new user with read-only rights and access to nothing but the pages you capture. Never borrow a person’s session. Why: OWASP: "the Least Privilege principle should be applied." A capture account that leaks can be deleted without locking anyone out.
3. **Keep the secret in server-side configuration.** Store it in a secret manager or an environment variable. Not in front-end code, not in a mobile app, not in the repository. Why: Anything shipped to a browser can be read by its user, and OWASP lists secrets hardcoded in source code as the problem secrets management exists to solve.
4. **Send it over HTTPS, in a body or a header.** Call the capture service from your server with `POST`, and capture an `https://` address. Why: OWASP: "it is essential to use an encrypted HTTPS (TLS) connection for the entire web session." URLs are kept in web logs, browser history and `Referer` headers even with HTTPS.
5. **Prove you are signed in before the capture.** Wait for an element that exists only on the signed-in page, such as the account menu, and fail when it does not appear. Why: An expired session does not produce an error. It produces a sharp screenshot of the login page, which then lands in a report or an email.
6. **Rotate it, and let it expire.** Give tokens and links the shortest life that works, replace long-lived secrets on a schedule, and replace them at once when someone leaves the team. Why: OWASP: "You should regularly rotate secrets so that any stolen credentials will only work for a short time."
7. **Treat the screenshot as sensitive data.** Store it where the page’s data would be allowed to live, give download links an expiry, and do not post it to a public channel. Why: The image shows whatever the account can see: names, revenue, invoices. A leaked screenshot is a data leak, with or without the secret.
8. **Take the key back when the job ends.** Log the session out, revoke the token or delete the capture account when the captures stop. Why: A secret nobody uses still works for whoever finds it.

## Never do this

- **Put a password or a session token in a query string.** URLs are stored in web logs, browser history and caches, and travel in `Referer` headers. OWASP: "Simply using HTTPS does not resolve this vulnerability." RFC 6750 says the same of bearer tokens.
- **Reuse an administrator’s personal session.** A session is worth as much as that person’s login. If it leaks, everything an administrator can do is exposed, and ending the session logs a colleague out.
- **Commit a cookie or a token to a repository.** Git keeps every version. A secret that was committed once stays readable in the history after the line is deleted, so it has to be rotated, not removed.
- **Send the secret from front-end code.** Whatever a browser runs, its user can read. A capture request with a cookie in it belongs on your server.
- **Capture over plain `http://`.** Basic credentials cross the network in clear text, a `Secure` cookie is not sent at all, and RFC 6750 requires TLS for bearer tokens.
- **Script the login form, a CAPTCHA or a second factor.** Those checks exist to stop automated sign-ins. Working around them means storing a real password in a script, and on a site that is not yours it breaks its rules.
- **Capture accounts that are not yours.** Everything on this page is for pages you are authorised to open. Using someone else’s session or password without permission is unauthorised access, whatever tool sends the request.

## Why the screenshot shows the login page, and other failures

### The screenshot shows the login page

- Domain mismatch. A cookie set without a `Domain` is host-only: it goes back to the exact host that set it and not to its subdomains.
- Path mismatch. A cookie with `Path=/app` is sent for `/app` and `/app/reports`, not for `/reports`.
- `Secure` on an `http://` address. A `Secure` cookie is sent only with `https:` requests.
- The session expired, or the user logged out, which ends the session on the server.
- A `__Host-` cookie sent with a `Domain`. That prefix requires `Secure`, `Path=/` and no `Domain` attribute.

Fix: Copy the Domain and Path columns exactly as the browser shows them, capture the `https://` address, and sign in again for a fresh value. Then add a signed-in check so the next expiry is an error and not an image.

### The screenshot shows a 401 or 403 error

- The token expired or was revoked, or the scheme word is missing: the value must read `Bearer <token>` or `Basic <base64>`.
- The token is valid but lacks the right for this page, which is a `403`.
- The site redirected to another origin. Browsers strip the `Authorization` header from cross-origin redirects.

Fix: Request the page with the same header from a terminal first. When that works, capture the final address, after any redirect, and check the rights of the token.

### The capture ends on the identity provider, or loops

- The application did not recognise the session and sent the browser to its single sign-on provider, a different host that has no session for it.
- You copied the provider’s cookie and not the application’s. The application keeps its own session cookie on its own domain after the sign-on completes.

Fix: Finish the sign-on yourself in a browser, then copy the session cookie of the application’s own domain. Do not try to replay the sign-on flow. If sessions are short, ask for a service token or build an expiring link.

### A "verify it is you" or new-device page appears

- The site ties a session to the device, browser or IP address it was created from, and the capture arrives from somewhere else.
- The site challenges automated browsers before it looks at your session at all.

Fix: This is the site’s protection doing its job, so do not work around it. On your own application, issue a token or a signed link for captures. On someone else’s, ask them for an automation token or an export.

### The page is signed in, but the data is missing

- A single-page application loads its data after the first paint, sometimes after it refreshes a short-lived token, and the capture came first.
- The data comes from a second host. A host-only cookie is not sent to `api.example.com`, and `SameSite=Strict` or `Lax` cookies are not sent on cross-site subrequests.
- The application keeps its token in the browser’s local storage, which a cookie or a header cannot fill.

Fix: Wait for an element that only appears with the data. For a second host on the same site, send the cookie with a `Domain` that covers both, such as `.example.com`. For a token in local storage, an expiring link to a server-rendered version of the page is the reliable route.

## How to find your session cookie

A session cookie is as powerful as your password while the session lives. Copy it only from an account made for captures.

1. Sign in to the site in a private window, as the account made for captures.
2. Open the developer tools with `F12`, or right-click the page and choose Inspect.
3. In Chrome, open Application, then Storage, then Cookies, and select the site’s origin.
4. In Firefox, open the Storage panel and choose Cookies.
5. Find the session cookie. Its name often contains `session`, `sid` or `auth`, and its HttpOnly column is usually ticked.
6. Copy the Value, and note the Domain, Path and Secure columns: the capture needs them to match.
7. Close the private window without logging out. Logging out ends the session you just copied.

Chrome and Firefox both show these columns for each cookie: Name, Value, Domain, Path, Expires / Max-Age, HttpOnly, Secure, SameSite.

## How CurlShot takes each key

| Key | Option | Format | Limits |
| --- | --- | --- | --- |
| Session cookie | `cookies` | A list of objects with `name` and `value`, plus optional `domain`, `path`, `secure`, `http_only`, `same_site` and `expires`. A cookie can also be one string: `"session=...; Domain=example.com; Secure"`. | Up to 50 cookies, each value up to 4,096 characters. Without `domain`, the cookie belongs to the host of `url`. |
| Bearer token | `authorization` | The whole header value as one string: `"Bearer YOUR_TOKEN"`. | Up to 4,096 characters. Sent only to the origin of `url`. |
| Basic authentication | `authorization` | `"Basic "` followed by the base64 of `user:password`. | An address with a name and password in it, such as `https://user:pass@example.com`, is refused with `invalid_options`. |
| A token in a custom header | `headers` | An object of names and values: `{ "X-Preview-Token": "..." }`. | Up to 50 headers, each value up to 4,096 characters. Ten connection-level headers cannot be set, among them `Host`, `Content-Length` and `Proxy-Authorization`. |
| Signed or expiring link | `url` | The link itself. No credential option is needed. | The address is kept in your screenshot history with the value of a signature, token or password parameter masked. Other parts of the address are stored as sent, so give the link a short expiry. |

A request with a session cookie:

```bash
curl -X POST "https://curlshot.com/api/v1/screenshot" \
  -H "X-Access-Key: $SCREENSHOT_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/reports/monthly",
    "cookies": [
      {
        "name": "session",
        "value": "PASTE_SESSION_COOKIE_VALUE",
        "domain": "example.com",
        "secure": true
      }
    ],
    "wait_for_selector": "#account-menu",
    "full_page": true
  }' \
  --output report.png
```

A request with a bearer token:

```bash
curl -X POST "https://curlshot.com/api/v1/screenshot" \
  -H "X-Access-Key: $SCREENSHOT_ACCESS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/reports/monthly",
    "authorization": "Bearer PASTE_READ_ONLY_TOKEN",
    "wait_for_selector": "#account-menu"
  }' \
  --output report.png
```

`wait_for_selector` is the signed-in check: if `#account-menu` never appears, the answer is a `selector_not_found` error and not a screenshot of the login page.

What happens to a secret you send:

- **Credentials go to one origin.** The `authorization` value and any header whose name contains `auth`, `cookie`, `token`, `secret`, `key` or `password` are sent only to requests for the origin of `url`: the same scheme, host and port. Fonts, analytics and other hosts the page loads from do not receive them, and neither does a site the page redirects to. Cookies follow their `Domain`, as in any browser.
- **Stored records are masked.** The record of a request that CurlShot keeps for your history stores every cookie value, the `authorization` value and those credential headers as `[redacted]`. Cookie names, domains and the other options are kept.
- **Credentials in the address are masked.** The `url` of a request is saved with the record and shown in your history. The value of a query parameter that is named like a credential (`signature`, `sig`, `token`, `access_token`, `password`, `api_key`, the `X-Amz-` and `X-Goog-` signature fields and similar) is stored as `redacted`. A secret under another name, or in the path, is stored as sent, so keep secrets out of the address or make them expire.
- **Background jobs hold the request until it is rendered.** A job sent with `async` or through a bulk call waits in a queue with its full options, credentials included, because the renderer needs them. A finished job is removed from the queue within one hour and a failed one within 7 days.
- **Nothing fills in a login form.** There is no option that types a name and a password, and none that answers a CAPTCHA or a second factor. You sign in; the API receives the result.
- **Private addresses are refused.** A `url` that resolves to `localhost`, a private range such as `10.0.0.0/8`, `172.16.0.0/12` or `192.168.0.0/16`, or a link-local address is refused with `host_not_allowed`. The page must be reachable from the public internet.

More in the [guide to cookies, headers and HTTP credentials](https://curlshot.com/docs/guides/screenshot-behind-login), the [tool page](https://curlshot.com/tools/screenshot-behind-login) and [Customize the page](https://curlshot.com/docs/customize).

## Pages on an intranet or localhost

A capture service on the public internet cannot open a page on a private network. Three things work:

- Run a headless browser inside the network, next to the page. It is the only setup that reaches an address the internet cannot.
- Render the report to HTML on your own server and send that HTML to the capture service with the `html` option. No login is involved, because your server already has the data.
- Publish the one page through a public `https://` host that checks a signed, expiring link, and capture that link.

## Glossary

- **Session cookie:** A small named value a site gives the browser after a successful login. The browser sends it back with every request, and the site uses it to find the signed-in session. (Browsers also use "session cookie" for any cookie without an expiry date.)
- **Bearer token:** A secret string sent in the `Authorization` header. Whoever holds ("bears") it can use it; no further proof is asked.
- **Basic authentication:** The oldest HTTP login scheme: the name and password joined by a colon, base64-encoded, and sent with every request.
- **Signed URL:** A link that carries an expiry time and a signature computed with a key only the server knows. The server can tell that the link is its own and has not been changed.
- **Scope:** The list of things a credential is allowed to do, such as "read reports". A narrower scope means a smaller leak.
- **Least privilege:** The rule that an account or a secret gets only the rights its job needs, and nothing else.
- **Blast radius:** Everything that is exposed if one secret leaks: which data, which actions, and for how long.
- **Single sign-on (SSO):** A setup where one identity provider handles the login for many applications. Each application still keeps its own session afterwards.

## Questions

### How do I take a screenshot of a page that requires a login?

Sign in to the site yourself, then give the capture tool proof of that session: the session cookie, a bearer token, HTTP Basic credentials, or a signed link your application made for that page. The tool opens the page already signed in. Use a dedicated read-only account, keep the secret on your server, and send it over HTTPS.

### Is it safe to send a session cookie to a screenshot service?

It carries the same risk as giving that service the login, for as long as the session lives, so limit what the session can do. Use an account made for captures with read-only rights, send the cookie in a POST body over HTTPS from your server, check how the service stores and logs request data, and log the session out when the job ends.

### Can a screenshot tool log in through single sign-on or two-factor authentication?

Not by typing credentials, and it should not try. Single sign-on and two-factor checks are built to stop automated logins. What works is to complete the sign-in yourself in a browser and pass the resulting session cookie of the application, or to use a token or an expiring link that the application issues for automation.

### Why does my screenshot show the login page and not the dashboard?

The site did not accept the session. The usual causes are an expired session, a cookie sent for the wrong domain or path, a Secure cookie used with an http address, or a logout that ended the session. Copy the Domain and Path exactly as the browser shows them, capture the https address, and sign in again for a fresh cookie.

### Where do I find my session cookie?

In the developer tools of your browser. In Chrome, open Application, then Storage, then Cookies, and select the site. In Firefox, open the Storage panel and choose Cookies. Copy the Value of the session cookie and note its Domain and Path. Treat it like a password: while the session lives, it opens the account.

### Can a cloud screenshot service capture a page on my intranet or localhost?

No. A service on the public internet cannot reach a private address, and a careful one refuses to try: CurlShot rejects localhost and private network ranges with a host_not_allowed error. Run a headless browser inside the network, send the page as HTML, or publish the one page behind a signed, expiring link.

### What does CurlShot do with the cookies and headers I send?

CurlShot sends the authorization value and credential-like headers only to the origin of the page you capture, and cookies only to their domain. In the stored record of the request, cookie values, the authorization value and those headers are replaced with "[redacted]". In the stored address, the value of a parameter named like a credential (signature, token, password) is masked too; a secret under any other name is stored as sent, so keep secrets out of the address or make them expire.

## Sources

1. OWASP Cheat Sheet Series, "Session Management Cheat Sheet": https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html (checked 11 October 2026)
2. OWASP Cheat Sheet Series, "Secrets Management Cheat Sheet": https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html (checked 11 October 2026)
3. OWASP Cheat Sheet Series, "Logging Cheat Sheet": https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html (checked 11 October 2026)
4. OWASP Community, "Information exposure through query strings in URL": https://community.owasp.org/vulnerabilities/Information_exposure_through_query_strings_in_url (checked 11 October 2026)
5. MDN Web Docs, "Set-Cookie header": https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie (checked 11 October 2026)
6. MDN Web Docs, "Authorization header": https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Authorization (checked 11 October 2026)
7. IETF, "RFC 6265: HTTP State Management Mechanism": https://www.rfc-editor.org/rfc/rfc6265 (checked 11 October 2026)
8. IETF, "RFC 7617: The ‘Basic’ HTTP Authentication Scheme": https://www.rfc-editor.org/rfc/rfc7617 (checked 11 October 2026)
9. IETF, "RFC 6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage": https://www.rfc-editor.org/rfc/rfc6750 (checked 11 October 2026)
10. Chrome DevTools, "View, add, edit, and delete cookies": https://developer.chrome.com/docs/devtools/application/cookies (checked 11 October 2026)
11. Firefox Source Docs, "Storage Inspector: Cookies": https://firefox-source-docs.mozilla.org/devtools-user/storage_inspector/cookies/index.html (checked 11 October 2026)
12. Amazon S3 User Guide, "Download and upload objects with presigned URLs": https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html (checked 11 October 2026)

## Go deeper

- [Screenshot a page behind a login](https://curlshot.com/tools/screenshot-behind-login)
- [Guide: cookies, headers and HTTP credentials](https://curlshot.com/docs/guides/screenshot-behind-login)
- [Customize the page before the capture](https://curlshot.com/docs/customize)
- [Signed links for the screenshot request itself](https://curlshot.com/docs/signed-links)

## Read next

- [Screenshot API vs headless browser: the real cost](https://curlshot.com/blog/screenshot-api-vs-headless-browser.md): A cost calculator with every assumption editable, the hidden work behind headless Chrome, and an honest checklist for build or buy.
- [Why website screenshots look wrong, and the fixes](https://curlshot.com/blog/why-website-screenshots-look-wrong.md): A field guide to 11 ways a website screenshot goes wrong, from blank lazy images to cookie banners and cut-off pages, with the cause and the fix for each.
- [Capture a web page as evidence that holds up](https://curlshot.com/blog/web-page-as-evidence.md): A checklist for saving a web page as a credible record: what to capture, how to fix the time with a hash and timestamp, and what makes a screenshot weak.
