Basic Auth Header Generator

Build an HTTP Basic Authorization header from a username and password, or paste one in and get the credentials back. You also get ready-to-run curl, fetch, Python and wget lines, with shell quoting that survives a password containing an apostrophe.

Credentials

What you type stays in this tab. The page builds the header with JavaScript and makes no request with it.

Header and examples
Basic auth is Base64 encoding, not encryption. Anyone who sees the header has the password, so only send it over HTTPS.

1 Basic Auth Header Generator example

Credentials

username: Aladdin
password: open sesame

Header

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

2 How the header is built

Join the username and password with a colon, encode that string as UTF-8 bytes, Base64 the bytes, and put Basic and a space in front. That is the whole scheme in RFC 7617. There is no hashing, no nonce and no timestamp, so the same credentials always produce the same header, and one line of code decodes it. The Decode mode here does that.

Encode to UTF-8 before Base64. Hand-rolled versions usually break at this step. In a browser, btoa("user:pässword") either throws or encodes Latin-1 bytes, depending on the character, and the server then sees a different password. RFC 7617 lets a server announce charset="UTF-8" in its challenge; most modern servers assume it. This page always encodes UTF-8, and when decoding it falls back to Latin-1 and says so if the bytes are not valid UTF-8.

3 When Basic auth is fine and when it is not

Use Basic auth only over HTTPS. With that in place it works well for a machine client talking to an API, a staging site behind a password, or a webhook receiver. The credentials are sent with every request, so keep them out of logs: many proxies and APM tools record headers by default. Avoid putting them in the URL (https://user:pass@host/): some browsers block it, and the URL ends up in shell history, bookmarks and server logs.

There is no logout, since the browser caches the credentials until it is closed, and no protection against guessing beyond whatever rate limiting you add. For end users, use a login form with sessions or tokens instead.

How to use the Basic Auth Header Generator tool

  1. Leave Mode on Encode and type the Username and Password. Show reveals the password while you check it.
  2. Optionally change the URL used in the examples. The right panel shows the header plus curl, fetch, Python requests and wget lines.
  3. Copy Header copies just the Authorization line; Copy All copies everything in the panel.
  4. To go the other way, switch Mode to Decode and paste a header. Copy Password then copies the decoded password.
  5. Dummy Data loads the RFC 7617 example (Aladdin / open sesame); Clear empties every field.

How to send and read Basic auth in JavaScript, Python and PHP

JavaScript (browser and Node.js)

function basicAuth(user, pass) {
  // btoa() only takes Latin-1, so go through UTF-8 bytes first
  const bytes = new TextEncoder().encode(user + ":" + pass);
  return "Basic " + btoa(String.fromCharCode(...bytes));
}

console.log(basicAuth("Aladdin", "open sesame")); // Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

// Sending it (fetch rejects credentials embedded in the URL)
// await fetch("https://api.example.com/", { headers: { Authorization: basicAuth("user", "pass") } });

// Decoding on the server (Node.js)
function parseBasic(header) {
  const m = /^Basic\s+(.+)$/i.exec(header || "");
  if (!m) return null;
  const text = Buffer.from(m[1], "base64").toString("utf8");
  const i = text.indexOf(":");
  return i < 0 ? null : { user: text.slice(0, i), pass: text.slice(i + 1) };
}
console.log(parseBasic("Basic dGVzdDoxMjPCow==")); // { user: 'test', pass: '123£' }

In Node.js alone, Buffer.from(user + ":" + pass).toString("base64") does the UTF-8 step for you.

Python

import base64

def basic_auth(user, password):
    raw = f"{user}:{password}".encode("utf-8")
    return "Basic " + base64.b64encode(raw).decode("ascii")

print(basic_auth("Aladdin", "open sesame"))

def parse_basic(header):
    scheme, _, token = header.partition(" ")
    if scheme.lower() != "basic":
        return None
    user, sep, password = base64.b64decode(token).decode("utf-8").partition(":")
    return (user, password) if sep else None

print(parse_basic("Basic dGVzdDoxMjPCow=="))

# With the requests library the header is built for you:
# requests.get("https://api.example.com/", auth=("user", "pass"))

PHP

<?php
$header = 'Basic ' . base64_encode('Aladdin:open sesame');
echo $header, PHP_EOL;

// Sending it with cURL
$ch = curl_init('https://api.example.com/');
curl_setopt($ch, CURLOPT_USERPWD, 'user:pass');   // cURL builds the header
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// $body = curl_exec($ch);

// Reading it on the server
$user = $_SERVER['PHP_AUTH_USER'] ?? null;
$pass = $_SERVER['PHP_AUTH_PW'] ?? null;
if ($user === null || !hash_equals('expected-secret', (string) $pass)) {
    header('WWW-Authenticate: Basic realm="Staging", charset="UTF-8"');
    http_response_code(401);
    exit('Unauthorized');
}

PHP_AUTH_USER is empty under PHP-FPM behind some Apache and nginx setups. Pass the Authorization header through (for example CGIPassAuth On) or parse HTTP_AUTHORIZATION yourself.

Common errors and how to fix them

401 Unauthorized even though the password is right
Non-ASCII characters are the usual cause: the client encoded Latin-1 and the server expected UTF-8, or the reverse. Decode the header here and check the charset line. Also check for a trailing newline copied into the password.
InvalidCharacterError: Failed to execute 'btoa' on 'Window'
btoa() was given a character above U+00FF. Encode to UTF-8 bytes first, as in the JavaScript snippet.
The browser keeps sending old credentials after I change them
Browsers cache Basic credentials per realm until the window is closed, and there is no logout. Use a private window to test, or change the realm string.
curl -u with a password containing ! or $ fails in the shell
The shell expanded it before curl saw it. Use single quotes, as in the generated examples, or put the credentials in a .netrc file and use --netrc.

Good to know

RFC 7617 defines the scheme and lets a server ask for UTF-8 by adding charset="UTF-8" to its WWW-Authenticate challenge. Clients that ignore it may still send Latin-1, which is why the decoder falls back to Latin-1 and says so when the bytes are not valid UTF-8.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

How is the Basic auth header built?

Join username and password with a colon, encode that as UTF-8, Base64 the bytes, and send Authorization: Basic followed by the result. Aladdin and open sesame become QWxhZGRpbjpvcGVuIHNlc2FtZQ==.

Is Basic authentication secure?

Only over HTTPS. The header is Base64, which anyone can decode, so over plain HTTP the password is effectively sent in clear text on every request.

How do I decode a Basic auth header?

Switch Mode to Decode and paste the header, with or without the Authorization: and Basic parts. The username and password are split at the first colon.

Can the username contain a colon?

No. The server splits at the first colon, so a colon in the username ends up in the password. The password itself may contain colons.

Is my password sent anywhere?

No. The header and examples are built with JavaScript in this tab and the page makes no request with them. As with any credential, avoid typing a production password on a shared machine.

Related

The header is plain Base64, so the Base64 encoder shows the raw step. Bearer tokens are usually JWTs, which the JWT decoder reads, and if you need a strong password to put in the header, use the password generator.

More Security & Hashing Tools

Browse all security & hashing tools

Copied to clipboard!