Repository: ktorio/ktor
File: ktor-client/ktor-client-plugins/ktor-client-auth/common/src/io/ktor/client/plugins/auth/providers/BasicAuthProvider.kt (Kotlin)

Code before:

    override suspend fun addRequestHeaders(request: HttpRequestBuilder, authHeader: HttpAuthHeader?) {
        val credentials = tokensHolder.loadToken() ?: return
        request.headers[HttpHeaders.Authorization] = constructBasicAuthValue(credentials)
    }

    override suspend fun refreshToken(response: HttpResponse): Boolean {
        tokensHolder.setToken(credentials)
        return true
    }

    /**
     * Clears the currently stored authentication tokens from the cache.
     *
     * This method should be called in the following cases:
     * - When the credentials have been updated and need to take effect
     * - When you want to force re-authentication
     * - When you want to clear sensitive authentication data
     *
     * Note: The result of [credentials] invocation is cached internally.
     * Calling this method will force the next authentication attempt to fetch fresh credentials.
     *
     * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.client.plugins.auth.providers.BasicAuthProvider.clearToken)
     */
    public fun clearToken() {
        tokensHolder.clearToken()
    }
}

internal fun constructBasicAuthValue(credentials: BasicAuthCredentials): String {
    val authString = "${credentials.username}:${credentials.password}"
    val authBuf = authString.toByteArray(Charsets.UTF_8).encodeBase64()

    return "Basic $authBuf"
}


Review comment (security):
We could make this method a part of `AuthProvider` interface, but it would be potentially breaking change. Only if not declare an empty implementation by default.
However, it makes sense for me to make `clearToken` a required for auth provider.

Code after:

    override suspend fun addRequestHeaders(request: HttpRequestBuilder, authHeader: HttpAuthHeader?) {
        val credentials = tokensHolder.loadToken() ?: return
        request.headers[HttpHeaders.Authorization] = constructBasicAuthValue(credentials)
    }

    override suspend fun refreshToken(response: HttpResponse): Boolean {
        tokensHolder.setToken(credentials)
        return true
    }

    /**
     * Clears the currently stored authentication tokens from the cache.
     *
     * This method should be called in the following cases:
     * - When the credentials have been updated and need to take effect
     * - When you want to force re-authentication
     * - When you want to clear sensitive authentication data
     *
     * Note: The result of [credentials] invocation is cached internally.
     * Calling this method will force the next authentication attempt to fetch fresh credentials.
     *
     * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.client.plugins.auth.providers.BasicAuthProvider.clearToken)
     */
    @InternalAPI // TODO KTOR-8180: Provide control over tokens to user code
    public fun clearToken() {
        tokensHolder.clearToken()
    }
}

internal fun constructBasicAuthValue(credentials: BasicAuthCredentials): String {
    val authString = "${credentials.username}:${credentials.password}"
    val authBuf = authString.toByteArray(Charsets.UTF_8).encodeBase64()

    return "Basic $authBuf"
}