The following section describes the Quarkus built-in authentication mechanisms for HTTP based FORM, BASIC, and Mutual TLS authentication. Proactive authentication is also described.
Basic Authentication
HTTP Basic Authentication uses fields in the HTTP header and is the easiest to set up. Also, it is one of the least resource-demanding techniques that enforce access controls to the Web resources without requiring HTTP cookies, session identifiers, or login pages.
In the context of an HTTP request, Basic authentication is a method for an HTTP user agent, such as a web browser, to provide a user name and password when creating a request. In Basic HTTP Authentication, a request contains a header field in the form of Authorization: Basic <credentials>
, where credentials are the Base64 encoding of a user ID and password joined by a colon as described in the following example.
If the user name is Alice
and the password is secret
, the HTTP authorization header looks authorization as Authorization: Basic QWxjZTpzZWNyZXQ=
, where QWxjZTpzZWNyZXQ=
is a Base64 encoded representation of the Alice:secret
string.
The Basic Authentication mechanism does not provide confidentiality protection for the transmitted credentials. The credentials are merely encoded with Base64 when in transit and not encrypted or hashed in any way. Therefore, Basic Authentication is used with HTTPS to provide confidentiality.
Enabling Basic Authentication
-
You have installed at least one extension that provides an
IdentityProvider
based on username and password, such as Elytron JDBC.
-
Enable Basic Authentication by setting the value of
quarkus.http.auth.basic
property totrue
.quarkus.http.auth.basic=true
For a Basic Authentication configuration walk-through that uses JPA
, see the Getting Started With Security guide.
Form Based Authentication
Quarkus provides form based authentication that works in a similar manner to traditional Servlet form based auth. Unlike traditional form authentication, the authenticated user is not stored in an HTTP session, as Quarkus does not provide clustered HTTP session support. Instead, the authentication information is stored in an encrypted cookie, which can be read by all members of the cluster (provided they all share the same encryption key).
The encryption key can be set using the quarkus.http.auth.session.encryption-key
property, and it must be at least 16 characters
long. This key is hashed using SHA-256 and the resulting digest is used as a key for AES-256 encryption of the cookie
value. This cookie contains an expiry time as part of the encrypted value, so all nodes in the cluster must have their
clocks synchronized. At one minute intervals a new cookie will be generated with an updated expiry time if the session
is in use.
The following properties can be used to configure form based auth:
Configuration property fixed at build time - All other configuration properties are overridable at runtime
Type |
Default |
|
---|---|---|
If form authentication is enabled Environment variable: |
boolean |
|
The login page Environment variable: |
string |
|
The post location. Environment variable: |
string |
|
The username field name. Environment variable: |
string |
|
The password field name. Environment variable: |
string |
|
The error page Environment variable: |
string |
|
The landing page to redirect to if there is no saved page to redirect back to Environment variable: |
string |
|
Option to disable redirect to landingPage if there is no saved page to redirect back to. Form Auth POST is followed by redirect to landingPage by default. Environment variable: |
boolean |
|
Option to control the name of the cookie used to redirect the user back to where he wants to get access to. Environment variable: |
string |
|
The inactivity (idle) timeout When inactivity timeout is reached, cookie is not renewed and a new login is enforced. Environment variable: |
|
|
How old a cookie can get before it will be replaced with a new cookie with an updated timeout, also referred to as "renewal-timeout". Note that smaller values will result in slightly more server load (as new encrypted cookies will be generated more often), however larger values affect the inactivity timeout as the timeout is set when a cookie is generated. For example if this is set to 10 minutes, and the inactivity timeout is 30m, if a users last request is when the cookie is 9m old then the actual timeout will happen 21m after the last request, as the timeout is only refreshed when a new cookie is generated. In other words no timeout is tracked on the server side; the timestamp is encoded and encrypted in the cookie itself, and it is decrypted and parsed with each request. Environment variable: |
|
|
The cookie that is used to store the persistent session Environment variable: |
string |
|
About the Duration format
The format for durations uses the standard You can also provide duration values starting with a number.
In this case, if the value consists only of a number, the converter treats the value as seconds.
Otherwise, |
Mutual TLS Authentication
Quarkus provides mTLS authentication so that you can authenticate users based on their X.509 certificates.
To use this authentication method, you should first enable SSL for your application. For more details, check the Supporting secure connections with SSL guide.
Once your application is accepting secure connections, the next step is to configure a quarkus.http.ssl.certificate.trust-store-file
holding all the certificates that your application should trust as well as how your application should ask for certificates when
a client (e.g.: browser or another service) tries to access one of its protected resources.
quarkus.http.ssl.certificate.key-store-file=server-keystore.jks (1)
quarkus.http.ssl.certificate.key-store-password=the_key_store_secret
quarkus.http.ssl.certificate.trust-store-file=server-truststore.jks (2)
quarkus.http.ssl.certificate.trust-store-password=the_trust_store_secret
quarkus.http.ssl.client-auth=required (3)
quarkus.http.auth.permission.default.paths=/* (4)
quarkus.http.auth.permission.default.policy=authenticated
1 | Configures a key store where the server’s private key is located. |
2 | Configures a trust store from where the trusted certificates are going to be loaded from. |
3 | Defines that the server should always ask certificates from clients. You can relax this behavior by using REQUEST so
that the server should still accept requests without a certificate. Useful when you are also supporting authentication methods other than
mTLS. |
4 | Defines a policy where only authenticated users should have access to resources from your application. |
Once the incoming request matches a valid certificate in the truststore, your application should be able to obtain the subject by
just injecting a SecurityIdentity
as follows:
@Inject
SecurityIdentity identity;
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return String.format("Hello, %s", identity.getPrincipal().getName());
}
You should also be able to get the certificate as follows:
import java.security.cert.X509Certificate;
import io.quarkus.security.credential.CertificateCredential;
CertificateCredential credential = identity.getCredential(CertificateCredential.class);
X509Certificate certificate = credential.getCertificate();
Authorization
The information from the client certificate can be used to enhance Quarkus SecurityIdentity
. For example, one can add new roles after checking a client certificate subject name, and so on.
Please see the SecurityIdentity Customization section for more information about customizing Quarkus SecurityIdentity
.
Proactive Authentication
By default, Quarkus does what we call proactive authentication. This means that if an incoming request has a credential then that request will always be authenticated (even if the target page does not require authentication).
This means that requests with an invalid credential will always be rejected, even for public pages. You can change
this behavior and only authenticate when required by setting quarkus.http.auth.proactive=false
.
If you disable proactive authentication then the authentication process will only be run when an identity is requested, either because there are security rules that requires the user to be authenticated, or due to programmatic access to the current identity.
Note that if proactive authentication is in use accessing the SecurityIdentity
is a blocking operation. This is because
authentication may not have happened yet, and accessing it may require calls to external systems such as databases that
may block. For blocking applications this is no problem, however if you have disabled authentication in a reactive
application this will fail (as you cannot do blocking operations on the IO thread). To work around this you need to
@Inject
an instance of io.quarkus.security.identity.CurrentIdentityAssociation
, and call the
Uni<SecurityIdentity> getDeferredIdentity();
method. You can then subscribe to the resulting Uni
and will be notified
when authentication is complete and the identity is available.
It’s still possible to access the SecurityIdentity synchronously with public SecurityIdentity getIdentity()
in the RESTEasy Reactive from endpoints annotated with @RolesAllowed , @Authenticated ,
or with respective configuration authorization checks as authentication has already happened. The same is also valid
for the Reactive routes if a route response is synchronous.
|
How to customize authentication exception responses
By default, the authentication security constraints are enforced before the JAX-RS chain starts.
Disabling the proactive authentication effectively shifts this process to the moment when the JAX-RS chain starts running thus making it possible to use JAX-RS ExceptionMapper
to capture Quarkus Security authentication exceptions such as io.quarkus.security.AuthenticationFailedException
, for example:
package io.quarkus.it.keycloak;
import javax.annotation.Priority;
import javax.ws.rs.Priorities;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import io.quarkus.security.AuthenticationFailedException;
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFailedExceptionMapper implements ExceptionMapper<AuthenticationFailedException> {
@Context
UriInfo uriInfo;
@Override
public Response toResponse(AuthenticationFailedException exception) {
return Response.status(401).header("WWW-Authenticate", "Basic realm=\"Quarkus\"").build();
}
}