using quarkus jwt token in micronaut application

Viewed 42

I have two microservices

  1. auth-service developed using Quarkus to generate JWT token.

  2. i developed the 2nd service using Micronaut (service1). I need to authenticate end points using auth-service. Can anyone please explain how to achieve it.

Please find the both services in the following

https://github.com/microservices-j/auth-service

https://github.com/microservices-j/service1

I generated the token using auth-service

and i pass the token into service1, but i am getting unauthorized.

> > Task :run  __  __ _                                  _    |  \/  (_) ___ _ __ ___  _ __   __ _ _   _| |_  | |\/| | |/ __| '__/ _ \| '_ \ / _` | | | | __| | |  | | | (__| | | (_) | | | | (_| | |_| | |_  |_|  |_|_|\___|_|  \___/|_| |_|\__,_|\__,_|\__|   Micronaut (v3.6.3)
> 
> 12:49:25.382 [main] DEBUG i.m.s.a.AuthenticationModeCondition -
> CookieBasedAuthenticationModeCondition is not fulfilled because
> micronaut.security.authentication is not one of [cookie, idtoken].
> 12:49:25.678 [main] INFO  io.micronaut.runtime.Micronaut - Startup
> completed in 1157ms. Server Running: http://localhost:8082
> 12:50:13.738 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.s.a.AuthenticationModeCondition -
> CookieBasedAuthenticationModeCondition is not fulfilled because
> micronaut.security.authentication is not one of [cookie, idtoken].
> 12:50:13.755 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.s.t.reader.HttpHeaderTokenReader - Looking for bearer token in
> Authorization header 12:50:13.755 [default-nioEventLoopGroup-1-2]
> DEBUG i.m.s.t.reader.DefaultTokenResolver - Request GET, /swagger-ui,
> no token found. 12:50:13.759 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.security.rules.IpPatternsRule - One or more of the IP patterns
> matched the host address [0:0:0:0:0:0:0:1]. Continuing request
> processing. 12:50:13.762 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.s.rules.AbstractSecurityRule - The given roles [[isAnonymous()]]
> matched one or more of the required roles [[isAnonymous()]]. Allowing
> the request 12:50:13.762 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.security.filters.SecurityFilter - Authorized request GET
> /swagger-ui. The rule provider
> io.micronaut.security.rules.ConfigurationInterceptUrlMapRule
> authorized the request. 12:50:14.734 [default-nioEventLoopGroup-1-2]
> DEBUG i.m.s.t.reader.HttpHeaderTokenReader - Looking for bearer token
> in Authorization header 12:50:14.734 [default-nioEventLoopGroup-1-2]
> DEBUG i.m.s.t.reader.DefaultTokenResolver - Request GET,
> /swagger/service1-0.0.yml, no token found. 12:50:14.735
> [default-nioEventLoopGroup-1-2] DEBUG
> i.m.security.rules.IpPatternsRule - One or more of the IP patterns
> matched the host address [0:0:0:0:0:0:0:1]. Continuing request
> processing. 12:50:14.736 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.s.rules.InterceptUrlMapRule - No url map pattern exact match found
> for path [/swagger/service1-0.0.yml] and method [GET]. Searching in
> patterns with no defined method. 12:50:14.736
> [default-nioEventLoopGroup-1-2] DEBUG i.m.s.rules.InterceptUrlMapRule
> - Url map pattern found for path [/swagger/service1-0.0.yml]. Comparing roles. 12:50:14.736 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.s.rules.AbstractSecurityRule - The given roles [[isAnonymous()]]
> matched one or more of the required roles [[isAnonymous()]]. Allowing
> the request 12:50:14.736 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.security.filters.SecurityFilter - Authorized request GET
> /swagger/service1-0.0.yml. The rule provider
> io.micronaut.security.rules.ConfigurationInterceptUrlMapRule
> authorized the request. 12:50:38.395 [default-nioEventLoopGroup-1-2]
> DEBUG i.m.s.t.reader.HttpHeaderTokenReader - Looking for bearer token
> in Authorization header 12:50:38.395 [default-nioEventLoopGroup-1-2]
> DEBUG i.m.s.t.reader.DefaultTokenResolver - Token
> eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwbXMiLCJzdWIiOiJkZW1vLnVzZXIiLCJpYXQiOjE2NjMzNDY5OTcsImV4cCI6MTY2MzM0NzI5NywianRpIjoiOGM1Mzc2ODMtOGM4Yy00MjgyLWFiYWUtMTU2Yzg3MjgzNGZhIn0.SxCAUxryW315Q3WlRSk6PypUh9s6K-Wce3zrB5Hmycs
> found in request GET /hello 12:50:38.418
> [default-nioEventLoopGroup-1-2] DEBUG
> i.m.s.t.jwt.validator.JwtValidator - Validating signed JWT
> 12:50:38.473 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.security.filters.SecurityFilter - Attributes: sub=>demo.user,
> iss=>pms, exp=>Fri Sep 16 12:54:57 EDT 2022, iat=>Fri Sep 16 12:49:57
> EDT 2022, jti=>8c537683-8c8c-4282-abae-156c872834fa 12:50:38.474
> [default-nioEventLoopGroup-1-2] DEBUG
> i.m.security.rules.IpPatternsRule - One or more of the IP patterns
> matched the host address [0:0:0:0:0:0:0:1]. Continuing request
> processing. 12:50:38.474 [default-nioEventLoopGroup-1-2] DEBUG
> i.m.s.rules.AbstractSecurityRule - None of the given roles
> [[isAnonymous(), isAuthenticated()]] matched the required roles [[]].
> Rejecting the request 12:50:38.474 [default-nioEventLoopGroup-1-2]
> DEBUG i.m.security.filters.SecurityFilter - Unauthorized request GET
> /hello. The rule provider
> io.micronaut.security.rules.SecuredAnnotationRule rejected the
> request. <===========--> 85% EXECUTING [6m 23s]
> > :run
> > IDLE
1 Answers

In your Quarkus application your are generating a signed JWT.

ApplicationScoped
@PermitAll
@Path("/login")
class LoginResource {

    @Produces(MediaType.TEXT_PLAIN)
    @Path("/")
    @POST
    fun login() : Response {

        val token =  Jwt
            .issuer("pms")
            .subject("demo.user")
            .sign()

        return Response.ok(token).build()
    }
}

In your Quarks application properties you use a Public/Private key pair to sign the JWT.

quarkus.http.port=8081

smallrye.jwt.sign.key.location=/Users/bala/labs/auth-service/jwt/privateKey.pem
mp.jwt.verify.issuer=demo
mp.jwt.verify.publickey.location=/Users/bala/labs/auth-service/jwt/publicKey.pem

But in the Micronaut microservice you are trying to validate the JWT using a secret to validate the JWT.

micronaut:
  server:
    port: 8082
  application:
    name: service1
  security:
    authentication: bearer
    basic-auth:
      enabled: false # <-- Add this to disable basic auth
    token:
      jwt:
        signatures:
          secret:
            generator:
              secret: ${JWT_GENERATOR_SIGNATURE_SECRET:pleaseChangeThisSecretForANewOne}

Of course this fails.

You have the following two options.

  1. The easy one. Make Quarkus generate signed JWT using a secret.
  2. The other option. Use the Public Key in Micronaut to validate the JWT (see RSASignatureConfiguration)

For option 2) you have to add an addition bean to the application context.

@Singleton
@Named
class MySignatureConfig : RSASignatureConfiguration {
    override fun getPublicKey(): RSAPublicKey {
        val encoded: ByteArray = Base64.getDecoder().decode("<your public key as a string>")

        val keyFactory: KeyFactory = KeyFactory.getInstance("RSA")
        val keySpec = X509EncodedKeySpec(encoded)
        return keyFactory.generatePublic(keySpec) as RSAPublicKey
    }
}

This will help to validate the JWT.

Additionally this is how Micronaut Security works, in the Basic Authentication Flow. Simply exchange AuthenticationFetcher with TokenAuthenticationFetcher. The helps debugging the flow.

Authentication Flow

Related