NTLM still appears on IIS applications, Windows-backed intranet APIs, and other legacy HTTP endpoints that expect a domain account instead of a browser session. When the same protected URL needs to be tested from a terminal, curl can complete the NTLM challenge-response exchange directly.
An NTLM-protected server usually answers the first unauthenticated request with 401 Unauthorized and a WWW-Authenticate: NTLM header. In curl, --ntlm enables the NTLM handshake and --user supplies the domain-qualified account in the form DOMAIN\username:password.
NTLM is best treated as a compatibility path rather than a preferred long-term authentication method. Keep it on HTTPS, avoid leaving reusable passwords on the literal command line when possible, and remember that some minimal curl builds do not include NTLM support at all, which shows up as an unsupported option or missing feature instead of an authentication failure.
$ curl --verbose --output /dev/null https://reports-api.example.com/reports/weekly-summary * Host reports-api.example.com:443 was resolved. ##### snipped ##### > GET /reports/weekly-summary HTTP/2 > Host: reports-api.example.com > Accept: */* < HTTP/2 401 < WWW-Authenticate: NTLM ##### snipped #####
A 401 plus WWW-Authenticate: NTLM means the origin server is asking for NTLM. If the response is 407 Proxy Authentication Required with Proxy-Authenticate: NTLM, the proxy is challenging first and the proxy-authentication path is the correct next step.
$ curl --ntlm --user 'OPS\svc-report-readonly:REDACTED_NTLM_PASSWORD' --write-out '\nHTTP %{http_code}\n' https://reports-api.example.com/reports/weekly-summary
{
"report": "weekly-summary",
"status": "ok",
"authenticated_as": "OPS\\svc-report-readonly"
}
HTTP 200
Inline credentials are easy to copy into notes, shell history, and terminal scrollback, so use this form for short local tests rather than long-lived automation.
$ curl --ntlm --user 'OPS\svc-report-readonly' --write-out '\nHTTP %{http_code}\n' https://reports-api.example.com/reports/weekly-summary
Enter host password for user 'OPS\svc-report-readonly':
{
"report": "weekly-summary",
"status": "ok",
"authenticated_as": "OPS\\svc-report-readonly"
}
HTTP 200
The interactive prompt keeps the password out of the shell history, but it is not suitable for unattended jobs. For repeatable automation, store the credential in a private cURL config or netrc file instead of retyping it.
$ curl --silent --show-error --output /dev/null --write-out '%{http_code}\n' --ntlm --user 'OPS\svc-report-readonly:REDACTED_NTLM_PASSWORD' https://reports-api.example.com/reports/weekly-summary
200
A repeated 401 usually means the username, password, domain prefix, or upstream account mapping is wrong rather than a generic curl syntax problem.
$ curl --verbose --ntlm --user 'OPS\svc-report-readonly:REDACTED_NTLM_PASSWORD' --output /dev/null https://reports-api.example.com/reports/weekly-summary * Host reports-api.example.com:443 was resolved. ##### snipped ##### > GET /reports/weekly-summary HTTP/2 > Host: reports-api.example.com > Accept: */* < HTTP/2 401 < WWW-Authenticate: NTLM ##### snipped ##### * Server auth using NTLM with user 'OPS\svc-report-readonly' > Authorization: NTLM ***REDACTED_NTLM_TOKEN*** ##### snipped ##### < HTTP/2 200
Verbose output exposes NTLM tokens and request metadata, so keep traces local and redact them before sharing. Related: How to debug HTTP requests with cURL
Related: View request headers in cURL