ak config setup fails with UnknownIssuer for private CA because device flow uses reqwest 0.12 rustls-tls
Description
ak config setup fails to connect to an authentik instance whose HTTPS certificate is issued by a private CA installed in the Linux system trust store.
The same certificate chain is successfully validated by:
- OpenSSL
- curl
- reqwest 0.13 using
rustls-platform-verifier
However, the OAuth device flow used by ak fails with:
invalid peer certificate: UnknownIssuer
I was able to reproduce the issue independently of authentik using reqwest 0.12.28 with the rustls-tls feature.
Environment
authentik-cli: 0.62.0
- OS: Ubuntu 26.04
- authentik URL:
https://auth.example.internal
- Private PKI with:
- private Root CA installed in the system trust store
- intermediate issuing CA
- server certificate issued by the intermediate
- Server sends the leaf + intermediate certificates.
The private Root CA is correctly installed in /etc/ssl/certs and /etc/ssl/certs/ca-certificates.crt.
authentik CLI error
ak -v config setup \
--authentik-url https://auth.example.internal \
--profile test
Result:
Error running command: device flow setup failed
Caused by:
0: Network error: error sending request for url (https://auth.example.internal/application/o/device/)
1: error sending request for url (https://auth.example.internal/application/o/device/)
2: client error (Connect)
3: invalid peer certificate: UnknownIssuer
Location:
ak-cli/src/setup/mod.rs:88:25
Setting SSL_CERT_FILE does not help:
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
ak -v config setup \
--authentik-url https://auth.example.internal \
--profile test
It produces the same UnknownIssuer error.
System TLS validation succeeds
OpenSSL successfully validates the server:
openssl s_client \
-connect auth.example.internal:443 \
-servername auth.example.internal
Result:
Verify return code: 0 (ok)
curl also successfully connects to the authentik API over HTTPS.
Minimal reqwest 0.13 test succeeds
The following application succeeds using reqwest 0.13:
[package]
name = "rustls-test"
version = "0.1.0"
edition = "2024"
[dependencies]
reqwest = { version = "0.13", default-features = false, features = ["rustls"] }
tokio = { version = "1", features = ["full"] }
#[tokio::main]
async fn main() {
let client = reqwest::Client::new();
match client
.get("https://auth.example.internal/application/o/device/")
.send()
.await
{
Ok(r) => println!("OK: {}", r.status()),
Err(e) => {
println!("ERROR: {e:#}");
println!("DEBUG: {e:?}");
}
}
}
Result with:
reqwest 0.13.5
rustls-platform-verifier 0.7.0
rustls-webpki 0.103.15
is:
OK: 405 Method Not Allowed
The HTTP 405 is expected because the device endpoint requires POST. The important point is that TLS validation succeeds.
Minimal reqwest 0.12.28 reproduction
Changing only reqwest to:
reqwest = {
version = "=0.12.28",
default-features = false,
features = ["rustls-tls"]
}
reproduces the exact TLS failure:
ERROR: error sending request for url (https://auth.example.internal/application/o/device/)
DEBUG: reqwest::Error {
kind: Request,
...
source: hyper_util::client::legacy::Error(
Connect,
...
InvalidCertificate(UnknownIssuer)
)
}
During compilation this configuration pulls in webpki-roots.
Suspected cause
The OAuth device flow used by ak 0.62.0 depends on oauth-device-flows, which uses reqwest 0.12.x.
With reqwest 0.12, the rustls-tls feature uses the WebPKI root set rather than the operating system's native CA store.
Consequently, public CAs work, but private enterprise/internal CAs installed in the Linux system trust store are not trusted by this HTTP client.
This also explains why setting:
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
does not resolve the issue.
Expected behavior
ak should honor the operating system's trusted CA store, so an authentik instance using a private enterprise CA trusted by the host can be used with:
ak config setup --authentik-url https://auth.example.internal
Possible fix
For the reqwest 0.12 dependency used by the device flow, using native roots instead of WebPKI roots should allow private system CAs, for example:
features = ["rustls-tls-native-roots"]
Alternatively, migrating the device-flow HTTP client to reqwest 0.13 / rustls-platform-verifier should provide system trust-store integration.
The reqwest 0.13 test above confirms that the same private CA and server certificate work correctly through that stack.
Additional validation
The server certificate chain has also been explicitly verified with OpenSSL using the private Root CA and intermediate:
openssl verify \
-verbose \
-purpose sslserver \
-CAfile root-ca.pem \
-untrusted intermediate-ca.pem \
server.pem
Result:
Therefore the issue does not appear to be caused by an invalid server certificate chain.
ak config setupfails withUnknownIssuerfor private CA because device flow uses reqwest 0.12rustls-tlsDescription
ak config setupfails to connect to an authentik instance whose HTTPS certificate is issued by a private CA installed in the Linux system trust store.The same certificate chain is successfully validated by:
rustls-platform-verifierHowever, the OAuth device flow used by
akfails with:I was able to reproduce the issue independently of authentik using
reqwest 0.12.28with therustls-tlsfeature.Environment
authentik-cli:0.62.0https://auth.example.internalThe private Root CA is correctly installed in
/etc/ssl/certsand/etc/ssl/certs/ca-certificates.crt.authentik CLI error
ak -v config setup \ --authentik-url https://auth.example.internal \ --profile testResult:
Setting
SSL_CERT_FILEdoes not help:SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \ ak -v config setup \ --authentik-url https://auth.example.internal \ --profile testIt produces the same
UnknownIssuererror.System TLS validation succeeds
OpenSSL successfully validates the server:
Result:
curlalso successfully connects to the authentik API over HTTPS.Minimal reqwest 0.13 test succeeds
The following application succeeds using reqwest 0.13:
Result with:
is:
The HTTP 405 is expected because the device endpoint requires POST. The important point is that TLS validation succeeds.
Minimal reqwest 0.12.28 reproduction
Changing only reqwest to:
reproduces the exact TLS failure:
During compilation this configuration pulls in
webpki-roots.Suspected cause
The OAuth device flow used by
ak 0.62.0depends onoauth-device-flows, which uses reqwest 0.12.x.With reqwest 0.12, the
rustls-tlsfeature uses the WebPKI root set rather than the operating system's native CA store.Consequently, public CAs work, but private enterprise/internal CAs installed in the Linux system trust store are not trusted by this HTTP client.
This also explains why setting:
does not resolve the issue.
Expected behavior
akshould honor the operating system's trusted CA store, so an authentik instance using a private enterprise CA trusted by the host can be used with:Possible fix
For the reqwest 0.12 dependency used by the device flow, using native roots instead of WebPKI roots should allow private system CAs, for example:
Alternatively, migrating the device-flow HTTP client to reqwest 0.13 /
rustls-platform-verifiershould provide system trust-store integration.The reqwest 0.13 test above confirms that the same private CA and server certificate work correctly through that stack.
Additional validation
The server certificate chain has also been explicitly verified with OpenSSL using the private Root CA and intermediate:
Result:
Therefore the issue does not appear to be caused by an invalid server certificate chain.