A screen has nobody sitting at it, so a page behind a login has to be authenticated in advance. From code there are three routes, and they differ in where the credential ends up.
Request headers
Every web content item carries a set of HTTP headers the player sends with its request. This is the route for anything the page will accept as a header: basic auth, a bearer token, an API key.
The CLI has a shortcut for each of the two common cases. Both write an Authorization header.
screenly asset basic-auth <asset-uuid> alice=hunter2screenly asset bearer-auth <asset-uuid> eyJhbGciOi...For anything else, set headers directly. set-headers replaces the whole set, update-headers merges into what is already there.
screenly asset update-headers <asset-uuid> X-Api-Key=abc123,X-Tenant=eu-westOver the API it is the headers field, a JSON object of up to 50 entries.
curl -X PATCH \
'https://api.screenlyapp.com/api/v4.1/assets?id=eq.<asset-uuid>' \
-H "Authorization: Token $SCREENLY_API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"headers": {"Authorization": "Bearer eyJhbGciOi..."}}'Headers are readable. Unlike JavaScript injection, a GET on the asset returns them in full, so any token you store here can be read back by anyone holding an API token for the workspace. Issue a credential scoped to just the page being displayed, and rotate it on the same schedule as anything else you would put in a shared config.
Headers do not refresh themselves. A token with an expiry stops working when it expires, and something of yours has to patch the asset with a new one. That is a natural fit for the same job that mints the token.
Client certificates
For internal systems where you would rather the device proved its identity than carried a password. Each screen holds its own certificate, and the server serves the page only to devices that present one.
From code this is the client_cert_allowed boolean on the asset, which only exists in v4.1.
curl -X PATCH \
'https://api.screenlyapp.com/api/v4.1/assets?id=eq.<asset-uuid>' \
-H "Authorization: Token $SCREENLY_API_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"client_cert_allowed": true}'Turning the flag on is the small half. The server has to be configured to require and verify the certificate, and how you validate matters: see Pages behind a login for the certificate download and the server configuration, including why chain validation alone is not enough.
Session cookies
For a page whose login is an ordinary form and whose session lives in a cookie, the browser extension captures a session you established yourself. There is no API for this, by design: the credential never exists as text anywhere you could script against.
Scripted logins
When none of the above fit, because the login is multi-step or built out of JavaScript, drive the form with JavaScript injection. That field is write-only, which makes it the least bad place to put a credential in Screenly, though a script that types a password into a page is still a password in a form field.
Nothing here gets past multi-factor authentication or SSO. Neither can be completed on a player, so a page behind either needs a service account, a token, or a certificate instead.