I havea Quarkus Java application. It serves my GraphQL API.
I would like to authenticate requests with JsonWebTokens (JWT). I know that smallrye-graphql already has some built-in JWT functionality. But I need to extend that. I need to add a custom role to authenticated users and other customizations.
How can I tap into that? According to this Quarksu-Security documentation I tried to implement my own HttpAuthenticationMechanism
.
I have questions. See comments in code:
@Alternative
@Priority(1) // <======= io.quarkus.arc.Priority or javax.annotation.Priority ???????
@ApplicationScoped
public class MyCustomAuthMechanism implements HttpAuthenticationMechanism {
@Override
public Uni<SecurityIdentity> authenticate(RoutingContext context, IdentityProviderManager identityProviderManager) {
// ==========================
// This is what i am trying to archive. But this whole method is never called ???
// ==========================
QuarkusSecurityIdentity user = QuarkusSecurityIdentity.builder().addRole("CUSTOM_USER").build();
// This would be nice if it would be possible to access the JWT directly
//context.request().getHeader(HttpHeaderNames.AUTHORIZATION);
return Uni.createFrom().item(user);
}
@Override
public Uni<ChallengeData> getChallenge(RoutingContext context) {
return Uni.createFrom().item(new ChallengeData(HttpResponseStatus.UNAUTHORIZED.code(), HttpHeaderNames.AUTHORIZATION, null)); // <====== is this correct? What to return here?
}
@Override
public Set<Class<? extends AuthenticationRequest>> getCredentialTypes() {
// This is called, but this seems to be the problem? What to return here?????
return Collections.singleton(TokenAuthenticationRequest.class);
}
}
Thank you very much for any advice or even better example code. (ChatGPT has some, but very old outdated versions :-)
Or to phrase my question in a more general way: My client will send HTTP reqests with a "Authorization: Bearer ...JWT...data..." header. That JWT is signed and contains information that I need in the backend. What's the easiest way to fetch that information in Quarkus GraphQL ?
Tried another way. Without any custom class or anythign. Just default as described by Quarkus docs.
application.properties
Do I need to set only one or both of these properties???
smallrye.jwt.sign.key.location=META-INF/resources/jwtKey.json
smallrye.jwt.verify.key.location=META-INF/resources/jwtKey.json
META-INF/resources/jwtKey.json
{
"keys": [
{
"kty":"oct",
"kid":"secretKey",
"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0ga............Zr1Z9CAow"
}
]
}
And I create my JWT like this:
String JWT = Jwt.issuer("my_site")
.subject("TestUser11@liquido.vote")
.upn("upn@liquido.vote")
.groups(Collections.singleton("LIQUIDO_USER"))
.sign()
My GraphQL @Query
is simply annotated with @Authenticated
. But I get the error:
ERROR [io.sma.graphql] (vert.x-eventloop-thread-1) SRGQL012000: Data Fetching Error: io.quarkus.security.UnauthorizedException
Thanks for any hints or suggestions.
In the end this turned out to be simply about having the correct configuration and using the quarkus default security architecture.
No extra classes needed.
Put your symetric keys under META-INF/resources
and then configure
application.properties
# key for signing JWTs (we use a simple symmetric key)
smallrye.jwt.sign.key.location=liquidoJwtKey.json
smallrye.jwt.verify.key.location=liquidoJwtKey.json
smallrye.jwt.verify.algorithm=HS256
After login the server sends a self signed JWT back to the client. The client can then use this JWT to authenticate in future requests. The JWT will automatically be evaluated by quarkus. And you can configure authorization via annotations, e.g. in some controller
@RolesAllowed("admin")
public void adminOnlyMethod() { ... }