HTTP authentication header parsing and generation supporting multiple authentication schemes including Basic, Bearer, Digest, and custom schemes with flexible parameter handling.
sealed class HttpAuthHeader(val authScheme: String) {
abstract fun render(): String
abstract fun render(encoding: HeaderValueEncoding): String
override fun toString(): String
}class HttpAuthHeader.Single(
authScheme: String,
val blob: String
) : HttpAuthHeader(authScheme) {
override fun render(): String
override fun render(encoding: HeaderValueEncoding): String
}Used for authentication schemes that use a single token or credential, such as Bearer tokens.
class HttpAuthHeader.Parameterized(
authScheme: String,
val parameters: Map<String, String>
) : HttpAuthHeader(authScheme) {
override fun render(): String
override fun render(encoding: HeaderValueEncoding): String
fun withParameter(name: String, value: String): HttpAuthHeader.Parameterized
fun parameter(name: String): String?
}Used for authentication schemes that require multiple parameters, such as Digest authentication.
object AuthScheme {
const val Basic: String = "Basic"
const val Digest: String = "Digest"
const val Negotiate: String = "Negotiate"
const val OAuth: String = "OAuth"
const val Bearer: String = "Bearer"
}enum class HeaderValueEncoding {
QUOTED_WHEN_REQUIRED,
QUOTED_ALWAYS,
URI_ENCODE
}Controls how authentication parameter values are encoded in the header.
fun parseAuthorizationHeader(headerValue: String): HttpAuthHeader?
fun parseAuthorizationHeaders(headerValue: String): List<HttpAuthHeader>Parse Authorization header values into structured authentication objects.
// Creating Bearer token authentication
val bearerToken = HttpAuthHeader.Single(
authScheme = AuthScheme.Bearer,
blob = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
)
// Rendering the header value
val headerValue = bearerToken.render()
println(headerValue) // Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
// Using in HTTP request
val headers = headersOf(
HttpHeaders.Authorization to bearerToken.render()
)// Creating Basic authentication
val credentials = "username:password"
val encodedCredentials = Base64.getEncoder().encodeToString(credentials.toByteArray())
val basicAuth = HttpAuthHeader.Single(
authScheme = AuthScheme.Basic,
blob = encodedCredentials
)
val authHeader = basicAuth.render()
println(authHeader) // Basic dXNlcm5hbWU6cGFzc3dvcmQ=
// Helper function for Basic auth
fun createBasicAuth(username: String, password: String): HttpAuthHeader.Single {
val credentials = "$username:$password"
val encoded = Base64.getEncoder().encodeToString(credentials.toByteArray())
return HttpAuthHeader.Single(AuthScheme.Basic, encoded)
}
val basicHeader = createBasicAuth("admin", "secret123")// Creating Digest authentication with parameters
val digestAuth = HttpAuthHeader.Parameterized(
authScheme = AuthScheme.Digest,
parameters = mapOf(
"username" to "admin",
"realm" to "api.example.com",
"nonce" to "dcd98b7102dd2f0e8b11d0f600bfb0c093",
"uri" to "/api/users",
"response" to "6629fae49393a05397450978507c4ef1",
"opaque" to "5ccc069c403ebaf9f0171e9517f40e41",
"qop" to "auth",
"nc" to "00000001",
"cnonce" to "0a4f113b"
)
)
val digestHeader = digestAuth.render()
println(digestHeader)
// Digest username="admin", realm="api.example.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", ...
// Adding parameters to existing auth header
val updatedDigest = digestAuth.withParameter("algorithm", "MD5")
val algorithmValue = updatedDigest.parameter("algorithm") // "MD5"// OAuth 1.0a signature authentication
val oauthAuth = HttpAuthHeader.Parameterized(
authScheme = AuthScheme.OAuth,
parameters = mapOf(
"oauth_consumer_key" to "xvz1evFS4wEEPTGEFPHBog",
"oauth_nonce" to "kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg",
"oauth_signature_method" to "HMAC-SHA1",
"oauth_timestamp" to "1318622958",
"oauth_token" to "370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb",
"oauth_version" to "1.0",
"oauth_signature" to "tnnArxj06cWHq44gCs1OSKk/jLY="
)
)
val oauthHeader = oauthAuth.render()
println(oauthHeader)
// OAuth oauth_consumer_key="xvz1evFS4wEEPTGEFPHBog", oauth_nonce="kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg", ...// Custom API key authentication
val apiKeyAuth = HttpAuthHeader.Single(
authScheme = "ApiKey",
blob = "ak_live_1234567890abcdef"
)
// Custom multi-parameter scheme
val customAuth = HttpAuthHeader.Parameterized(
authScheme = "CustomScheme",
parameters = mapOf(
"client_id" to "my-client-id",
"signature" to "computed-signature",
"timestamp" to System.currentTimeMillis().toString()
)
)
val customHeader = customAuth.render()
println(customHeader) // CustomScheme client_id="my-client-id", signature="computed-signature", ...val authWithSpecialChars = HttpAuthHeader.Parameterized(
authScheme = AuthScheme.Digest,
parameters = mapOf(
"username" to "user@domain.com",
"realm" to "My Realm With Spaces",
"response" to "hash/with+special=chars"
)
)
// Different encoding strategies
val quotedWhenRequired = authWithSpecialChars.render(HeaderValueEncoding.QUOTED_WHEN_REQUIRED)
val alwaysQuoted = authWithSpecialChars.render(HeaderValueEncoding.QUOTED_ALWAYS)
val uriEncoded = authWithSpecialChars.render(HeaderValueEncoding.URI_ENCODE)
println("Quoted when required: $quotedWhenRequired")
println("Always quoted: $alwaysQuoted")
println("URI encoded: $uriEncoded")// Parse single Authorization header
val authHeaderValue = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
val parsedAuth = parseAuthorizationHeader(authHeaderValue)
when (parsedAuth) {
is HttpAuthHeader.Single -> {
println("Scheme: ${parsedAuth.authScheme}") // Bearer
println("Token: ${parsedAuth.blob}") // JWT token
}
is HttpAuthHeader.Parameterized -> {
println("Scheme: ${parsedAuth.authScheme}")
println("Parameters: ${parsedAuth.parameters}")
}
null -> println("Failed to parse authorization header")
}
// Parse multiple Authorization headers (rare but possible)
val multipleHeaders = listOf(
"Bearer token123",
"Basic dXNlcjpwYXNz"
)
val parsedHeaders = parseAuthorizationHeaders(multipleHeaders)
parsedHeaders.forEach { auth ->
println("Parsed: ${auth.authScheme} - ${auth.render()}")
}val digestHeaderValue = """Digest username="admin", realm="api.example.com", nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", uri="/api/users", response="6629fae49393a05397450978507c4ef1", opaque="5ccc069c403ebaf9f0171e9517f40e41", qop="auth", nc="00000001", cnonce="0a4f113b""""
val parsedDigest = parseAuthorizationHeader(digestHeaderValue)
if (parsedDigest is HttpAuthHeader.Parameterized) {
println("Username: ${parsedDigest.parameter("username")}") // admin
println("Realm: ${parsedDigest.parameter("realm")}") // api.example.com
println("Nonce: ${parsedDigest.parameter("nonce")}") // dcd98b7102dd2f0e8b11d0f600bfb0c093
println("QOP: ${parsedDigest.parameter("qop")}") // auth
}// Helper function to create JWT Bearer auth
fun createJwtAuth(token: String): HttpAuthHeader.Single {
return HttpAuthHeader.Single(AuthScheme.Bearer, token)
}
// Helper function to create API key auth
fun createApiKeyAuth(apiKey: String, scheme: String = "ApiKey"): HttpAuthHeader.Single {
return HttpAuthHeader.Single(scheme, apiKey)
}
// Helper function to extract Bearer token
fun extractBearerToken(headers: Headers): String? {
val authHeader = headers[HttpHeaders.Authorization] ?: return null
val parsed = parseAuthorizationHeader(authHeader) ?: return null
return if (parsed is HttpAuthHeader.Single && parsed.authScheme == AuthScheme.Bearer) {
parsed.blob
} else {
null
}
}
// Helper function to validate Basic auth
fun validateBasicAuth(headers: Headers, expectedUsername: String, expectedPassword: String): Boolean {
val authHeader = headers[HttpHeaders.Authorization] ?: return false
val parsed = parseAuthorizationHeader(authHeader) ?: return false
if (parsed !is HttpAuthHeader.Single || parsed.authScheme != AuthScheme.Basic) {
return false
}
return try {
val decoded = String(Base64.getDecoder().decode(parsed.blob))
val (username, password) = decoded.split(":", limit = 2)
username == expectedUsername && password == expectedPassword
} catch (e: Exception) {
false
}
}
// Usage examples
val jwtAuth = createJwtAuth("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
val apiKeyAuth = createApiKeyAuth("ak_live_1234567890abcdef")
val requestHeaders = headersOf(
HttpHeaders.Authorization to jwtAuth.render()
)
val token = extractBearerToken(requestHeaders)
println("Extracted token: $token")// Safe parsing with error handling
fun parseAuthSafe(headerValue: String): HttpAuthHeader? {
return try {
parseAuthorizationHeader(headerValue)
} catch (e: Exception) {
println("Failed to parse auth header: ${e.message}")
null
}
}
// Validate auth header format
fun isValidAuthHeader(headerValue: String): Boolean {
return parseAuthorizationHeader(headerValue) != null
}
// Examples of invalid headers that will return null
val invalidHeaders = listOf(
"", // empty
"InvalidScheme", // no space or parameters
"Bearer", // missing token
"Digest incomplete=parameter" // malformed parameters
)
invalidHeaders.forEach { header ->
val result = parseAuthSafe(header)
println("'$header' -> ${result != null}")
}// Example of authentication handling in middleware
class AuthenticationHandler {
fun handleAuthentication(headers: Headers): AuthResult {
val authHeader = headers[HttpHeaders.Authorization]
?: return AuthResult.Missing
val parsed = parseAuthorizationHeader(authHeader)
?: return AuthResult.Invalid("Malformed authorization header")
return when (parsed) {
is HttpAuthHeader.Single -> when (parsed.authScheme) {
AuthScheme.Bearer -> validateBearerToken(parsed.blob)
AuthScheme.Basic -> validateBasicCredentials(parsed.blob)
else -> AuthResult.UnsupportedScheme(parsed.authScheme)
}
is HttpAuthHeader.Parameterized -> when (parsed.authScheme) {
AuthScheme.Digest -> validateDigestAuth(parsed)
AuthScheme.OAuth -> validateOAuthSignature(parsed)
else -> AuthResult.UnsupportedScheme(parsed.authScheme)
}
}
}
private fun validateBearerToken(token: String): AuthResult {
// JWT validation logic here
return AuthResult.Success("user-id-from-token")
}
private fun validateBasicCredentials(credentials: String): AuthResult {
// Basic auth validation logic here
return AuthResult.Success("user-id-from-basic")
}
private fun validateDigestAuth(auth: HttpAuthHeader.Parameterized): AuthResult {
// Digest auth validation logic here
return AuthResult.Success("user-id-from-digest")
}
private fun validateOAuthSignature(auth: HttpAuthHeader.Parameterized): AuthResult {
// OAuth signature validation logic here
return AuthResult.Success("user-id-from-oauth")
}
}
sealed class AuthResult {
object Missing : AuthResult()
data class Invalid(val reason: String) : AuthResult()
data class UnsupportedScheme(val scheme: String) : AuthResult()
data class Success(val userId: String) : AuthResult()
}