Customizing Firefox to Read HTTP Proxy Credentials from an fpfile
Join my Discord community to learn, share, and discuss together: https://discord.gg/rX2vkNNW
This article explains a small Firefox source-code customization for HTTP proxy
authentication.
The goal is simple: when Firefox receives an HTTP authentication challenge from
a password-protected proxy, it first tries to read the username and password from
a local fpfile passed through the --fpfile command-line argument. If the file
is missing, unreadable, or incomplete, Firefox falls back to its original
username/password prompt.
This is useful when running automated or customized Firefox builds where proxy
credentials should be provided by local runtime configuration instead of an
interactive dialog.
Modified File
The core change is in:
C:\firefox\firefox\netwerk\protocol\http\nsHttpChannelAuthProvider.cpp
Firefox enters nsHttpChannelAuthProvider::GetCredentialsForChallenge() when it
needs credentials for an HTTP authentication challenge. A proxy challenge, such
as 407 Proxy Authentication Required, also goes through this path.
Originally, Firefox called PromptForIdentity() directly when credentials were
required. The customized version first attempts to load credentials from the file
specified by --fpfile. Only if that fails does it call the original prompt.
New Includes
The file adds a few includes near the top:
#include <fstream>
#include <string>
#include "base/command_line.h"
#include "nsStringStream.h"
#include "mozilla/Base64.h"
For this HTTP proxy authentication change, the important ones are:
#include <fstream>
#include <string>
#include "base/command_line.h"
They are used to read the local fpfile, parse text, and access the current
process command-line arguments.
Where the Logic Lives
The new logic is placed inside GetCredentialsForChallenge(), around the area
where Firefox previously prompted for credentials.
The original flow was:
rv = PromptForIdentity(level, proxyAuth, realm, aAuthType, authFlags, *ident);
if (NS_FAILED(rv)) return rv;
identFromURI = false;
The customized flow is:
- Check whether the Firefox process was started with
--fpfile. - If it was, open that file.
- Read
httpauth.usernameandhttpauth.password. - If both values exist, create an
nsHttpAuthIdentity. - If anything fails, continue with Firefox's original prompt behavior.
Reading HTTP Auth Credentials from fpfile
The code first checks whether the current Firefox process has the fpfile
switch:
const char kRuyiFileSwitch[] = "fpfile";
if (CommandLine::ForCurrentProcess()->HasSwitch(UTF8ToWide(kRuyiFileSwitch))) {
std::wstring fpValue =
CommandLine::ForCurrentProcess()->GetSwitchValue(
UTF8ToWide(kRuyiFileSwitch));
If the switch has a value, the path is converted to UTF-8 and opened:
if (!fpValue.empty()) {
std::string fileName = WideToUTF8(fpValue);
std::fstream fs(fileName, std::ios::in);
if (fs.is_open()) {
Then the file is read line by line. Both : and = are accepted as separators:
std::string line;
std::string username;
std::string password;
while (std::getline(fs, line)) {
if (line.empty()) {
continue;
}
size_t delimPos = line.find_first_of(":=");
if (delimPos == std::string::npos ||
delimPos + 1 >= line.length()) {
continue;
}
std::string key = line.substr(0, delimPos);
std::string value = line.substr(delimPos + 1);
The key and value are trimmed, so spaces or tabs around them are allowed:
size_t keyStart = key.find_first_not_of(" \t");
if (keyStart == std::string::npos) {
continue;
}
size_t keyEnd = key.find_last_not_of(" \t");
key = key.substr(keyStart, keyEnd - keyStart + 1);
size_t valueStart = value.find_first_not_of(" \t");
if (valueStart == std::string::npos) {
value.clear();
} else {
size_t valueEnd = value.find_last_not_of(" \t");
value = value.substr(valueStart, valueEnd - valueStart + 1);
}
Only two keys are recognized:
if (key == "httpauth.username") {
username = value;
} else if (key == "httpauth.password") {
password = value;
}
When both values are present, Firefox creates an HTTP authentication identity:
if (!username.empty() && !password.empty()) {
*ident = nsHttpAuthIdentity(
EmptyString(), NS_ConvertUTF8toUTF16(username),
NS_ConvertUTF8toUTF16(password));
}
The first field, EmptyString(), is the domain. The next two fields are the
username and password.
Falling Back to Firefox's Original Prompt
If --fpfile is not provided, the file cannot be opened, the fields are missing,
or either credential is empty, ident remains empty. In that case, Firefox keeps
its original behavior and prompts the user:
if (ident->IsEmpty()) {
rv = PromptForIdentity(level, proxyAuth, realm, aAuthType, authFlags,
*ident);
if (NS_FAILED(rv)) return rv;
}
identFromURI = false;
In practice:
- If the fpfile contains both
httpauth.usernameandhttpauth.password, Firefox authenticates automatically without showing the prompt. - If the fpfile is missing, unreadable, or incomplete, Firefox behaves exactly as before and shows the username/password dialog.
fpfile Format
Start Firefox with:
--fpfile=C:\firefox\fp.txt
The fpfile can use =:
httpauth.username=your_user
httpauth.password=your_password
It can also use ::
httpauth.username: your_user
httpauth.password: your_password
Use real credentials only in your local fpfile. Do not put production proxy
passwords into documentation, code comments, commits, screenshots, or blog posts.
Important Behavior and Limitations
This implementation uses one global HTTP authentication username/password pair.
It does not currently match credentials by proxy host or port.
It also does not restrict the injected credentials to proxyAuth == true.
That means a normal website HTTP Basic or Digest challenge that reaches the same
authentication path may also receive this httpauth.* identity.
For a tighter production design, I would add at least two extra guards:
- Apply the fpfile credentials only when
proxyAuth == true. - Scope credentials by proxy host and port instead of using a single global pair.
Why This Approach
The main benefit is that the change is narrow and preserves Firefox's default
behavior as the fallback path.
The custom build can run without an interactive proxy credential prompt when
valid fpfile credentials are available. At the same time, normal Firefox behavior
still works when the file is absent or invalid.
This keeps the runtime configuration outside the profile and avoids saving proxy
credentials into Firefox preferences.
Summary
The customization changes Firefox's HTTP authentication flow so that proxy
credentials can be supplied through a local --fpfile configuration file.
The important pieces are:
- The change lives in
nsHttpChannelAuthProvider.cpp. - The code reads
httpauth.usernameandhttpauth.passwordfrom--fpfile. - It creates an
nsHttpAuthIdentityonly when both values are present. - If reading fails, Firefox falls back to
PromptForIdentity(). - Real passwords should stay in the local fpfile, not in public documentation.
Top comments (0)