Skip to main content
doc0blade47/honodocumentation home
Sign in

Basic and Bearer Auth

Last updated Oct 12, 2026100% grounded
Relevant source files

The following files were used as context for generating this wiki page:

Overview

Hono provides built-in middleware for HTTP Basic and Bearer Auth to secure API endpoints by validating credentials against static configurations or custom verification handlers. These middlewares inspect incoming request headers, parse authorization schemes, and dispatch standardized HTTP exceptions with 401 Unauthorized status codes and WWW-Authenticate challenge headers when verification fails.

Sources: src/middleware/basic-auth/index.ts:31-46, src/middleware/bearer-auth/index.ts:88-89

To prevent timing side-channel attacks during credential comparison, the system utilizes constant-time string and buffer comparison algorithms implemented within utility modules.

Sources: src/utils/buffer.ts:29-63

Basic Authentication Flow

Credential Matching Execution Walkthrough

The basicAuth middleware accepts an options object supporting either static username/password pairs or a custom verifyUser asynchronous callback function. The public configuration options also accept an optional realm, a hashFunction for credential normalization, an invalidUserMessage string, object, or message function, and an onAuthSuccess callback hook. If neither static credentials nor a verifyUser function are supplied, initialization throws an error.

Sources: src/middleware/basic-auth/index.ts:14-30, src/middleware/basic-auth/index.ts:80-91

Option KeyTypeDefault ValueDescription
usernamestring—Static username for authentication matching
passwordstring—Static password for authentication matching
verifyUserFunction—Custom verification handler taking (username, password, c)
realmstring"Secure Area"Realm attribute populated in the WWW-Authenticate header
hashFunctionFunctionsha256Hash function utilized during secure credential comparison
invalidUserMessagestring | object | Function"Unauthorized"Response body content returned on validation failure
onAuthSuccessFunction—Callback function invoked upon successful authentication

Sources: src/middleware/basic-auth/index.ts:36-43, src/middleware/basic-auth/index.ts:93-99

Note

When static username and password properties are specified in the configuration object alongside rest parameters (...users), they are prepended to the internal user verification array via users.unshift().

Sources: src/middleware/basic-auth/index.ts:81-83, src/middleware/basic-auth/index.ts:101-103

When an incoming request is intercepted, the handler extracts and parses authorization credentials from the request headers using the basic auth utility function, checking the provided username and password against configured accounts or the custom verification handler via the execution chain: basicAuth → timingSafeEqual → timingSafeEqualString → constantTimeEqualString.

Sources: src/middleware/basic-auth/index.ts:105-131, src/utils/buffer.ts:29-96

  1. basicAuth invokes auth(ctx.req.raw) to extract the decoded request username and password, then iterates through configured users to invoke timingSafeEqual(user.username, requestUser.username, options.hashFunction) and timingSafeEqual(user.password, requestUser.password, options.hashFunction) via Promise.all. Sources: src/middleware/basic-auth/index.ts:106-121
  2. timingSafeEqual checks argument types and routes string inputs to timingSafeEqualString. Sources: src/utils/buffer.ts:76-83
  3. timingSafeEqualString resolves the active hash function (defaulting to sha256), computes hashed byte representations of both strings in parallel via Promise.all, and passes the resulting digests to constantTimeEqualString. Sources: src/utils/buffer.ts:44-63
  4. constantTimeEqualString evaluates character codes across the maximum length utilizing bitwise operations to accumulate differences without early exits. Sources: src/utils/buffer.ts:29-40

Sources: src/middleware/basic-auth/index.ts:118-121, src/utils/buffer.ts:76-83, src/utils/buffer.ts:44-63, src/utils/buffer.ts:29-40

Parsing Authorization Credentials

Credential Extraction and Decoding

The Utilities and Encoding page documents how low-level helpers manage character encoding src/utils/encode.ts:1-4. Incoming HTTP requests are processed by the auth helper, which reads the Authorization header and matches it against CREDENTIALS_REGEXP to isolate the Base64-encoded payload portion src/utils/basic-auth.ts:3-10. If the header is missing or fails the regular expression pattern, the function immediately returns undefined src/utils/basic-auth.ts:10-13.

Sources: src/utils/basic-auth.ts:3-13, src/utils/encode.ts:1-4

Execution Walkthrough and Sequence

  1. basicAuth invokes auth(ctx.req.raw) to retrieve credentials from the raw request object src/middleware/basic-auth/index.ts:106. Sources: src/middleware/basic-auth/index.ts:106
  2. auth executes CREDENTIALS_REGEXP.exec on the header string, captures group 1, and passes it to decodeBase64 [[src/utils/basic-auth.ts:10], [src/utils/basic-auth.ts:18]]. Sources: [src/utils/basic-auth.ts:10](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/utils/basic-auth.ts#L10], [src/utils/basic-auth.ts:18)
  3. decodeBase64 invokes atob(str) and constructs a Uint8Array using byte character codes src/utils/encode.ts:25-33. Sources: src/utils/encode.ts:25-33

Sources: src/middleware/basic-auth/index.ts:106, src/utils/basic-auth.ts:10-18, src/utils/encode.ts:25-33

Regular Expressions and Sanitization

Constant NameRegular Expression PatternPurpose
CREDENTIALS_REGEXP/^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/Matches and extracts the Base64 token following the Basic scheme prefix.
USER_PASS_REGEXP/^([^:]*):(.*)$/Splits the decoded string into username and password components across the first colon.

Sources: src/utils/basic-auth.ts:3-4

Warning

If an invalid string is passed to atob(), a DOMException is thrown; the auth function catches this exception inside a try...catch block and safely returns undefined rather than crashing the request lifecycle.

Sources: src/utils/basic-auth.ts:15-20

Bearer Authentication Enforcement

Bearer Options and Header Processing

The bearerAuth middleware requires options containing either a token (string or array of strings) or a verifyToken function. Optional configurations include realm, prefix, headerName, hashFunction, and customized error responses via noAuthenticationHeader, invalidAuthenticationHeader, and invalidToken. If neither token nor verifyToken is provided, the middleware throws an initialization error.

Sources: src/middleware/bearer-auth/index.ts:22-50, src/middleware/bearer-auth/index.ts:107-109

Option NameTypeDefault ValuePurpose
tokenstring | string[]undefinedThe static token string or array of acceptable tokens.
verifyToken(token: string, c: Context) => boolean | Promise<boolean>undefinedCustom token verification callback function.
realmstring''Authentication realm string included in challenge headers.
prefixstring'Bearer'Expected scheme prefix preceding the token.
headerNamestring'Authorization'Custom header name to inspect instead of Authorization.
hashFunctionFunctionsha256Custom hashing function used during token comparison.

Sources: src/middleware/bearer-auth/index.ts:22-50, src/middleware/bearer-auth/index.ts:110-115, src/utils/buffer.ts:50

Note

When prefix is set to an empty string '', scheme prefix validation is bypassed entirely, and the entire header value is treated directly as the token string.

Sources: src/middleware/bearer-auth/index.ts:172-174

Execution Walkthrough and Sequence

  1. bearerAuth receives the request and inspects the specified HTTP header using c.req.header(options.headerName || HEADER). Sources: src/middleware/bearer-auth/index.ts:156-157
  2. If the header is missing, it dispatches an unauthorized exception via throwHTTPException with a 401 status. Sources: src/middleware/bearer-auth/index.ts:158-168
  3. If present, it validates the scheme prefix case-insensitively, trims leading whitespace, and tests the extracted token against tokenRegexp (^[A-Za-z0-9._~+/-]+=*$). Sources: src/middleware/bearer-auth/index.ts:12-19, src/middleware/bearer-auth/index.ts:175-182
  4. If token validation fails, a 400 Bad Request exception is thrown. Sources: src/middleware/bearer-auth/index.ts:182-192
  5. Otherwise, credential matching delegates to verifyToken or calls timingSafeEqual. Sources: src/middleware/bearer-auth/index.ts:195-206
  6. timingSafeEqual invokes timingSafeEqualString. Sources: src/utils/buffer.ts:76-83
  7. timingSafeEqualString invokes constantTimeEqualString for byte and hash verification. Sources: src/utils/buffer.ts:44-63

Sources: src/middleware/bearer-auth/index.ts:198, src/utils/buffer.ts:76-83, src/utils/buffer.ts:44-63, src/utils/buffer.ts:29-40

Timing-Attack Mitigation

Constant-Time Comparison Operations

Hono implements timing-attack mitigation utilities in src/utils/buffer.ts to prevent attackers from inferring secret tokens or passwords via response latency side channels. The lowest-level primitive, constantTimeEqualString, processes two strings character by character without short-circuiting on mismatch:

const constantTimeEqualString = (a: string, b: string): boolean => {
  const aLen = a.length
  const bLen = b.length
  const maxLen = Math.max(aLen, bLen)
  let out = aLen ^ bLen
  for (let i = 0; i < maxLen; i++) {
    const aChar = i < aLen ? a.charCodeAt(i) : 0
    const bChar = i < bLen ? b.charCodeAt(i) : 0
    out |= aChar ^ bChar
  }
  return out === 0
}

Sources: src/utils/buffer.ts:29-40

Caution

Length differences between strings are accumulated into the XOR accumulator via aLen ^ bLen, preventing length-extension leaks from exiting early when string lengths diverge.

Sources: src/utils/buffer.ts:33

ArrayBuffer and String Equivalence

Higher-level comparison functions handle binary ArrayBuffer instances as well as hashed and unhashed strings. The equal function compares two ArrayBuffer instances using a DataView iteration loop:

export const equal = (a: ArrayBuffer, b: ArrayBuffer): boolean => {
  if (a === b) {
    return true
  }
  if (a.byteLength !== b.byteLength) {
    return false
  }
 
  const va = new DataView(a)
  const vb = new DataView(b)
 
  let i = va.byteLength
  while (i--) {
    if (va.getUint8(i) !== vb.getUint8(i)) {
      return false
    }
  }
 
  return true
}

Sources: src/utils/buffer.ts:8-27

The timingSafeEqualString function wraps string hashing and comparison. By default, if no custom hashFunction is provided, it falls back to sha256:

const timingSafeEqualString = async (
  a: string,
  b: string,
  hashFunction?: StringHashFunction
): Promise<boolean> => {
  if (!hashFunction) {
    hashFunction = sha256
  }
 
  const [sa, sb] = await Promise.all([hashFunction(a), hashFunction(b)])
 
  if (sa == null || sb == null || typeof sa !== 'string' || typeof sb !== 'string') {
    return false
  }
 
  const hashEqual = constantTimeEqualString(sa, sb)
  const originalEqual = constantTimeEqualString(a, b)
 
  return hashEqual && originalEqual
}

Sources: src/utils/buffer.ts:44-63

Note

timingSafeEqualString evaluates both constantTimeEqualString(sa, sb) on the hashed outputs and constantTimeEqualString(a, b) on the raw inputs concurrently, returning true only if both comparisons succeed.

Sources: src/utils/buffer.ts:53-62

The exported timingSafeEqual entry point normalizes inputs and routes execution depending on whether parameters are strings or generic objects/booleans:

export const timingSafeEqual: TimingSafeEqual = async (
  a,
  b,
  hashFunction?: Function
): Promise<boolean> => {
  if (typeof a === 'string' && typeof b === 'string') {
    return timingSafeEqualString(a, b, hashFunction as StringHashFunction)
  }
 
  if (!hashFunction) {
    hashFunction = sha256
  }
 
  const [sa, sb] = await Promise.all([hashFunction(a), hashFunction(b)])
 
  if (!sa || !sb || typeof sa !== 'string' || typeof sb !== 'string') {
    return false
  }
 
  return timingSafeEqualString(sa, sb)
}

Sources: src/utils/buffer.ts:76-96

Authentication Challenges and Error Dispatch

HTTPException Instantiation and Response Generation

When authentication fails across Hono's authentication middlewares, error handling is dispatched via HTTPException combined with custom Response instances. The basicAuth middleware evaluates the parsed user credentials against configured options or user lists. Upon failure, it constructs a 401 Unauthorized status response containing the WWW-Authenticate header populated with the escaped realm name. If invalidUserMessage is configured as a function or an object, it is dynamically serialized into a text or JSON payload before throwing the HTTPException:

  // Invalid user.
  const status = 401
  const headers = {
    'WWW-Authenticate': 'Basic realm="' + options.realm?.replace(/"/g, '\\"') + '"',
  }
  const responseMessage =
    typeof options.invalidUserMessage === 'function'
      ? await options.invalidUserMessage(ctx)
      : options.invalidUserMessage
  const res =
    typeof responseMessage === 'string'
      ? new Response(responseMessage, { status, headers })
      : new Response(JSON.stringify(responseMessage), {
          status,
          headers: {
            ...headers,
            'content-type': 'application/json',
          },
        })
  throw new HTTPException(status, { res })
}

Sources: src/middleware/basic-auth/index.ts:132-152

Similarly, the bearerAuth middleware defines a private throwHTTPException helper function to encapsulate status codes, challenge headers, and message body construction. Depending on the specific failure branch—such as missing headers, malformed requests, or invalid tokens—it issues status codes 401, 400, or 401 respectively.

Sources: src/middleware/bearer-auth/index.ts:122-154

Warning

Realms containing double quotes are automatically escaped via options.realm?.replace(/"/g, '\\"') prior to header injection to prevent header injection vulnerabilities.

Sources: src/middleware/basic-auth/index.ts:135, src/middleware/bearer-auth/index.ts:117

WWW-Authenticate Challenge Construction

The construction of challenge headers differs between schemes based on whether options specify plain strings, objects, or callback functions. The bearerAuth middleware processes wwwAuthenticateHeader parameters by checking their type. If an object is supplied, its entries are mapped into comma-separated key-value pairs appended to the challenge prefix:

const wwwAuthenticateHeaderValue: string | object =
  typeof wwwAuthenticateHeader === 'function'
    ? await wwwAuthenticateHeader(c)
    : wwwAuthenticateHeader
 
const headers = {
  'WWW-Authenticate':
    typeof wwwAuthenticateHeaderValue === 'string'
      ? wwwAuthenticateHeaderValue
      : `${wwwAuthenticatePrefix}${Object.entries(wwwAuthenticateHeaderValue)
          .map(([key, value]) => `${key}="${value}"`)
          .join(',')}`,
}

Sources: src/middleware/bearer-auth/index.ts:128-140

For JSON Web Token workflows in jwt and jwk middlewares, failed verifications or missing tokens trigger unauthorizedResponse, which formats challenge headers including the current request URL, error codes, and detailed descriptions:

function unauthorizedResponse(opts: {
  ctx: Context
  error: string
  errDescription: string
  statusText?: string
}) {
  return new Response('Unauthorized', {
    status: 401,
    statusText: opts.statusText,
    headers: {
      'WWW-Authenticate': `Bearer realm="${opts.ctx.req.url}",error="${opts.error}",error_description="${opts.errDescription}"`,
    },
  })
}

Sources: src/middleware/jwt/jwt.ts:160-173, src/middleware/jwk/jwk.ts:170-182

MiddlewareDefault Status CodeDefault WWW-Authenticate ChallengeMessage Payload Handling
basicAuth401Basic realm="..."Text or JSON via invalidUserMessage
bearerAuth (Missing)401Bearer realm="..."Text or JSON via noAuthenticationHeader.message
bearerAuth (Invalid Request)400Bearer error="invalid_request"Text or JSON via invalidAuthenticationHeader.message
bearerAuth (Invalid Token)401Bearer error="invalid_token"Text or JSON via invalidToken.message
jwt / jwk401Bearer realm="...",error="...",error_description="..."Static string 'Unauthorized'

Sources: src/middleware/basic-auth/index.ts:133-151, src/middleware/bearer-auth/index.ts:160-215, src/middleware/jwt/jwt.ts:160-173, src/middleware/jwk/jwk.ts:170-182

Was this page helpful?