Using scripts for automated login on Sophos systems

Using scripts for automated login on Sophos systems

I spent several weeks automating captive portal logins at an education site. The wired network pushed devices through a Sophos captive portal, and phones and lab PCs kept dropping off unless someone signed in again. I wrote small scripts that posted credentials to the portal, then tied them into startup and network events. The useful bit is not the script itself. It is working out which part of the portal you are actually talking to.

Getting started

Campus and classroom networks often have devices that do not cope with browser-based login. Tablets, printers and some lab gear tend to fall over when they get redirected. That leaves them stuck without internet access. Sophos can present a captive portal or require a separate authentication client, and those do not always behave the same way. Check which method is in play before you try to automate anything.

What I do first:

  • Check whether the portal is a plain HTTP form, a JSON API, or an 802.1X flow. A browser login that takes username and password is usually a form POST. An authentication client often relies on certificate provisioning or RADIUS.
  • Log in manually in a browser and capture the request. I use the browser dev tools Network tab or tcpdump on a gateway.
  • Note the URLs, form field names, cookies, and any CSRF token. That gives you the pieces for a script.

Setting up the environment

Decide where the script will run. I usually use one of three setups:

  • A central gateway or travel router that stays authenticated and presents a single MAC address to the portal.
  • A single desktop that acts as a jump box and runs a scheduled login script.
  • Individual device scripts for lab PCs or Raspberry Pis.

On Linux, install curl, jq and cron or systemd. On Windows, use PowerShell and Task Scheduler. On macOS, use launchd or a cron wrapper. Keep the clock right. Time skew can break certificate-based flows.

Network behaviour to check:

  • DHCP lease behaviour. If the portal ties access to an IP or MAC, renewals may force re-authentication.
  • DNS and captive portal redirects. Some devices cache DNS, so a short TTL helps if you control local DNS.

Script requirements

Keep the script small and obvious. My checklist:

  • Handle HTTPS. If the portal uses HTTPS with an unknown CA, either import the CA into the device or point curl at a pinned certificate file. Do not disable certificate checks on production endpoints.
  • Preserve cookies and session headers. Use a cookie jar file or a PowerShell session object.
  • Retry with backoff. One failed POST should not lock the account.
  • Log success or failure to a file with timestamps.
  • Store credentials securely. On Linux, use a protected file with 600 permissions or a simple keyring. On Windows, use the credential manager and fetch credentials at runtime.

I do not hardcode passwords in scripts. For small labs I keep credentials in a file readable only by the service account and rotate them when the institution changes passwords.

Writing the script

Start by reproducing the browser POST. A typical Linux curl flow for a form POST looks like this:

#!/bin/bash

COOKIEJAR="/var/run/sophos_cookie.txt"
LOGIN_URL="https://10.0.0.1/login"
USERNAME="schooluser"
PASSFILE="/etc/sophos/pass"
PASSWORD="$(cat "$PASSFILE")"

# Get any CSRF token from the login page
TOKEN=$(curl -sk -c "$COOKIEJAR" "$LOGIN_URL" | sed -n 's/.*name="csrf" value="([^"]*)".*/1/p')

# Post credentials
curl -sk -b "$COOKIEJAR" -c "$COOKIEJAR" 
  -d "username=$USERNAME" 
  -d "password=$PASSWORD" 
  -d "csrf=$TOKEN" 
  "$LOGIN_URL" -o /tmp/sophos_login_response.html

# Check for a success marker in the response
grep -q "Welcome" /tmp/sophos_login_response.html && echo "$(date): login ok" >> /var/log/sophos_login.log

On Windows, use PowerShell Invoke-WebRequest with -SessionVariable for cookies. Keep the script short so you can debug each step.

If the portal uses JSON or an API, adapt the curl command to send a JSON body and set Content-Type: application/json. If the authentication client is required, scripts will not help; you need to deploy the client or use a device that can run it.

Testing the script

Test it manually before you automate it. I usually do this:

  1. Run the script while watching the browser dev tools or tcpdump. Check that the same requests go out.
  2. Check cookie files and response HTML for the values you expect.
  3. Break it on purpose with a wrong password and make sure the script logs a clear error.
  4. Test on a clean device that has never authenticated. That flushes out hidden dependencies such as required headers or referer checks.

Once the manual tests pass, run the script at boot or when the network interface comes up. On systemd systems, use a service unit that depends on network-online.target. On Windows, use Task Scheduler with a trigger for logon and network connect.

Troubleshooting common issues

Login fails but the browser login works:

  • The portal may tie the session to a user agent or browser fingerprint. Set the script to use the same User-Agent and headers as the browser.
  • Check for JavaScript-generated tokens. If the login page builds a token in JavaScript, you need to reproduce that logic or use a headless browser like Puppeteer for automation.

Certificates and HTTPS failures:

  • If curl complains about a self-signed CA, import the CA or point curl to a CA bundle. Do not skip verification on devices that handle sensitive data.
  • Check the device clock. Large clock drift can cause TLS failures.

Frequent re-authentication:

  • The portal may tie access to MAC or require client certificates. If it is MAC-based, use a travel router and MAC cloning to present one authenticated device to the portal while other devices sit behind NAT.
  • For client-certificate flows, deploy the client or the certificate to the devices that need persistent access.

Performance and lockouts:

  • Limit retries and add a cooldown. Too many failed attempts may lock the account. Log each attempt so you can spot loops.

Related posts

Monitoring radio, transport and core faults

Private 5G resilience does not come from a cheerful dashboard or a nice radio map. I want to see where the attach failed, which path dropped, and whether the core is quietly spoiling the whole thing;...

Immich | v3.2.2

Immich v3 2 2: small patch fixes cross user face reassign bug, skips faces owned by other accounts, recommended update for users relying on face reassign

Nextcloud | v35.0.0

Nextcloud v35: polished UI, Files and sharing upgrades, better client parity, security hardening, performance and admin gains, developer notes and upgrade tips