Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MACProvider NullPointerException when validating JWT #209

Closed
leonidasv opened this issue Apr 6, 2020 · 20 comments
Closed

MACProvider NullPointerException when validating JWT #209

leonidasv opened this issue Apr 6, 2020 · 20 comments

Comments

@leonidasv
Copy link

leonidasv commented Apr 6, 2020

We have a Micronaut application deployed via Kubernetes. We use 3 pods with the same image.

Our Micronaut setup has JWT enabled with Oauth2 via Cognito for authentication. Our main development language is Kotlin.

Locally, the setup works. However, in production and staging/develop environment, we are getting intermittent NullPointerExceptions from MACProvider.java after the pods have been running for a while. When a pod starts throwing this exception, it will throw it for every request, even if you log-out and log-in again or use a token that was previouslly working.

A pod failure seems to not affect the other running pods and it appears to happen randomly. So, when your request is routed to the failing pod, it will return a 500 HTTP status with {"message":"Internal Server Error: null"}. However, when your request is routed to a working pod, it works. So requests become intermittent: sometimes they work, sometimes they fail.

We have no idea about what causes it, neither how to properly debug it. This lead us to think this may be a bug or unintended behaviour from the Micronaut Security library.

The stacktrace is, as follows:

java.lang.NullPointerException: null
	at com.nimbusds.jose.crypto.impl.MACProvider.<init>(MACProvider.java:117)
	at com.nimbusds.jose.crypto.MACVerifier.<init>(MACVerifier.java:168)
	at com.nimbusds.jose.crypto.MACVerifier.<init>(MACVerifier.java:81)
	at io.micronaut.security.token.jwt.signature.secret.SecretSignature.verify(SecretSignature.java:78)
	at io.micronaut.security.token.jwt.validator.JwtTokenValidatorUtils.validateSignedJWTSignature(JwtTokenValidatorUtils.java:96)
	at io.micronaut.security.token.jwt.validator.JwtTokenValidatorUtils.parseJwtIfValidSignature(JwtTokenValidatorUtils.java:225)
	at io.micronaut.security.token.jwt.validator.JwtTokenValidatorUtils.validateJwtSignatureAndClaims(JwtTokenValidatorUtils.java:190)
	at io.micronaut.security.token.jwt.validator.JwtTokenValidator.validateJwtSignatureAndClaims(JwtTokenValidator.java:212)
	at io.micronaut.security.token.jwt.validator.JwtTokenValidator.authenticationIfValidJwtSignatureAndClaims(JwtTokenValidator.java:166)
	at io.micronaut.security.token.jwt.validator.JwtTokenValidator.validateToken(JwtTokenValidator.java:151)
	at io.micronaut.security.token.TokenAuthenticationFetcher.lambda$attemptTokenValidation$1(TokenAuthenticationFetcher.java:110)
	at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.onNext(FlowableSwitchMap.java:113)
	at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:68)
	at io.reactivex.internal.subscriptions.ScalarSubscription.request(ScalarSubscription.java:55)
	at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.request(FlowableSwitchMap.java:162)
	at io.reactivex.internal.subscriptions.SubscriptionArbiter.setSubscription(SubscriptionArbiter.java:99)
	at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty$SwitchIfEmptySubscriber.onSubscribe(FlowableSwitchIfEmpty.java:51)
	at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onSubscribe(RxInstrumentedSubscriber.java:54)
	at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.onSubscribe(FlowableSwitchMap.java:93)
	at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onSubscribe(RxInstrumentedSubscriber.java:54)
	at io.reactivex.internal.operators.flowable.FlowableJust.subscribeActual(FlowableJust.java:34)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.internal.operators.flowable.FlowableSwitchMap.subscribeActual(FlowableSwitchMap.java:49)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FlowableSwitchIfEmpty.java:71)
	at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onComplete(RxInstrumentedSubscriber.java:97)
	at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.drain(FlowableSwitchMap.java:225)
	at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.onComplete(FlowableSwitchMap.java:154)
	at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onComplete(RxInstrumentedSubscriber.java:97)
	at io.reactivex.internal.subscriptions.ScalarSubscription.request(ScalarSubscription.java:57)
	at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.request(FlowableSwitchMap.java:162)
	at io.reactivex.internal.subscriptions.SubscriptionArbiter.setSubscription(SubscriptionArbiter.java:99)
	at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty$SwitchIfEmptySubscriber.onSubscribe(FlowableSwitchIfEmpty.java:51)
	at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onSubscribe(RxInstrumentedSubscriber.java:54)
	at io.reactivex.internal.operators.flowable.FlowableSwitchMap$SwitchMapSubscriber.onSubscribe(FlowableSwitchMap.java:93)
	at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onSubscribe(RxInstrumentedSubscriber.java:54)
	at io.reactivex.internal.operators.flowable.FlowableJust.subscribeActual(FlowableJust.java:34)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.internal.operators.flowable.FlowableSwitchMap.subscribeActual(FlowableSwitchMap.java:49)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163)
	at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onNext(RxInstrumentedSubscriber.java:68)
	at io.reactivex.internal.operators.flowable.FlowableFromIterable$IteratorSubscription.slowPath(FlowableFromIterable.java:236)
	at io.reactivex.internal.operators.flowable.FlowableFromIterable$BaseRangeSubscription.request(FlowableFromIterable.java:124)
	at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onSubscribe(FlowableFlatMap.java:117)
	at io.micronaut.reactive.rxjava2.RxInstrumentedSubscriber.onSubscribe(RxInstrumentedSubscriber.java:54)
	at io.reactivex.internal.operators.flowable.FlowableFromIterable.subscribe(FlowableFromIterable.java:69)
	at io.reactivex.internal.operators.flowable.FlowableFromIterable.subscribeActual(FlowableFromIterable.java:47)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.internal.operators.flowable.FlowableFlatMap.subscribeActual(FlowableFlatMap.java:53)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.internal.operators.flowable.FlowableElementAtMaybe.subscribeActual(FlowableElementAtMaybe.java:36)
	at io.reactivex.Maybe.subscribe(Maybe.java:4290)
	at io.micronaut.reactive.rxjava2.RxInstrumentedMaybe.subscribeActual(RxInstrumentedMaybe.java:53)
	at io.reactivex.Maybe.subscribe(Maybe.java:4290)
	at io.reactivex.internal.operators.maybe.MaybeDoOnEvent.subscribeActual(MaybeDoOnEvent.java:39)
	at io.reactivex.Maybe.subscribe(Maybe.java:4290)
	at io.micronaut.reactive.rxjava2.RxInstrumentedMaybe.subscribeActual(RxInstrumentedMaybe.java:53)
	at io.reactivex.Maybe.subscribe(Maybe.java:4290)
	at io.reactivex.internal.operators.maybe.MaybeToFlowable.subscribeActual(MaybeToFlowable.java:45)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.internal.operators.flowable.FlowableFlatMap.subscribeActual(FlowableFlatMap.java:53)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.internal.operators.flowable.FlowableSwitchIfEmpty.subscribeActual(FlowableSwitchIfEmpty.java:32)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.micronaut.reactive.rxjava2.RxInstrumentedFlowable.subscribeActual(RxInstrumentedFlowable.java:58)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14868)
	at io.micronaut.configuration.metrics.binder.web.WebMetricsPublisher.subscribe(WebMetricsPublisher.java:153)
	at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52)
	at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:68)
	at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52)
	at io.micronaut.core.async.publisher.Publishers.lambda$map$2(Publishers.java:134)
	at io.reactivex.internal.operators.flowable.FlowableFromPublisher.subscribeActual(FlowableFromPublisher.java:29)
	at io.reactivex.Flowable.subscribe(Flowable.java:14918)
	at io.reactivex.Flowable.subscribe(Flowable.java:14865)
	at io.reactivex.internal.operators.flowable.FlowableSubscribeOn$SubscribeOnSubscriber.run(FlowableSubscribeOn.java:82)
	at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker$BooleanRunnable.run(ExecutorScheduler.java:288)
	at io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker.run(ExecutorScheduler.java:253)
	at io.micrometer.core.instrument.composite.CompositeTimer.record(CompositeTimer.java:79)
	at io.micrometer.core.instrument.Timer.lambda$wrap$0(Timer.java:144)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
@sdelamo
Copy link
Contributor

sdelamo commented Apr 16, 2020

which micronaut version and which version of Micronaut security ?

@dgbmariano
Copy link

micronaut-bom:1.3.3, micronaut-security-jwt:1.3.0, micronaut.configuration:micronaut-security-oauth2:1.3.0

@ronhitchens
Copy link

We are experiencing the identical intermittent failure on a system that we are trying to prepare for Production. For us it is happening on AWS Elastic Beanstalk, with Micronaut version 1.3.4 and the Auth0 OAuth setup. We see exactly the same stack trace. It appears that in class SecretSignature an incomplete config bean was injected. It seems that config.getSecret() is returning null, which sets up a later NPE because the byte array secret in that class never gets initialized.

For us, it appears that it's an intermittent startup problem. Sometimes the EB instance starts up fine and everything runs with no problem. Other times something seems to go wrong and the config is not picked up correctly. We've not seen it fail after it has started up ok. I added a test endpoint (anonymous) to display the JVM environment variables and the expected env vars are present and have the expected values as set in the AWS config. The handful of unprotected endpoints we have seem to respond as expected, but anything that requires JWT validation blows up.

We set the system-specific properties via env vars. In the case of the ...secret.generator.secret property, there is a default value in application.yaml and one set in the environment as MICRONAUT_SECURITY_TOKEN_JWT_SIGNATURES_SECRET_GENERATOR_SECRET. So it definitely should never be undefined.

This appears to be a race condition or some other timing-dependent issue. When it happens, we can bounce the app and it will usually startup ok with no problems. Sometimes it will have the problem several times in a row. We're not sure, but it seems to happen more frequently now.

It would be helpful if this null pointer was handled more gracefully. Preferably, by preventing startup and reporting an explanation in the log. As it is, end users see something that looks broken and the stack trace in the log does not offer any clues.

Please advise when a fix is available for this. It's holding up our upgrade to production (planned for this week) until we can rely on deployments running smoothly. Please let me know if I can provide any additional information. Unfortunately, I don't know where to go from here in terms of debugging the code myself.

@graemerocher
Copy link
Contributor

Thanks for the report. The NPE does need to be handled more gracefully but I believe a better fix is to add more validation at startup.

Could you try this as a workaround whilst we investigate:

@Context
@Named("generator")
class GeneratorSecretSignature extends SecretSignature {
      GeneratorSecretSignature(@Property(name="generator.secret") String secret) {
           super(createSecretConfig(secret));
      }

     private static SecretSignatureConfiguration createSecretConfig(String secret) {
           SecretSignatureConfiguration config = new SecretSignatureConfiguration("generator");
           config.setSecret(secret);
           return config;
      }  
}

Then set GENERATOR_SECRET environment variable.

If you are able to provide an example with steps to reproduce (even if it happens intermittently) that would help too.

Thanks for the report.

@ronhitchens
Copy link

Thank you for the workaround. I was about to do something like that anyway so you've saved me the trouble of creating the bean myself. I only hope it doesn't have the same issue resolving that property as it does the original one. If it does, I guess that will be a useful thing to know.

In terms of more gracefully handling the exception, I was referring to startup as well as a more helpful error message. JWT signing/verification is an essential service and the app is useless without it. Perhaps it's a good idea to have the initialization for JWT done eagerly so that Micronaut can abort startup if there's a problem, rather than waiting for the first use of JWT validation. When it's deferred as it is, the AWS console shows that the app has started up and is responded fine to hearbeat requests. Even when users are seeing errors, the status of the app shows green.

I can share info about the AWS Elastic Beanstalk instance we're using if that would be helpful. It's pretty generic. We use Terraform to configure them. We've had similar instances running for well over a year running Micronaut apps with no problems. We're building and deploying with CodeFresh, Shippable before that. Only on the dev branch where we're implementing the switch to Auth0 has this issue popped up, so I think it's something specific to that codebase. When we deploy a new build, or change environment variables, and reboot, this problem randomly occurs.

We could probably give you access to the instance when it's experiencing the problem (though I don't know what you could discover from that). We'd also be happy to test candidate fixes for you if need be. This is a showstopper bug for us at the moment (fingers crossed for the workaround).

Thanks

@graemerocher
Copy link
Contributor

Yes I agree that the verification should be done as early as possible. Thanks for your feedback

@dgbmariano
Copy link

Thanks for the workaround. We will test and post here the results.

@dgbmariano
Copy link

Tried, but we now receive an 401 response.

@dgbmariano
Copy link

dgbmariano commented Apr 27, 2020

Some notes:
Without the workaround, setting GENERATOR_SECRET environment variable instead of MICRONAUT_SECURITY_TOKEN_JWT_SIGNATURES_SECRET_GENERATOR_SECRET seems to make this error stop. I don't have any idea of why this is working.

@graemerocher
Copy link
Contributor

Yes with my suggested workaround you have to remove MICRONAUT_SECURITY_TOKEN_JWT_SIGNATURES_SECRET_GENERATOR_SECRET

@dgbmariano
Copy link

dgbmariano commented Apr 27, 2020

I removed the MICRONAUT_SECURITY_TOKEN_JWT_SIGNATURES_SECRET_GENERATOR_SECRET and added the GENERATOR_SECRET with the workaround and didn't work (I was getting 401 responses). Then I removed the workaround and let only the GENERATOR_SECRET environment variable and worked

@dgbmariano
Copy link

Just to update: Just renaming the environment variable MICRONAUT_SECURITY_TOKEN_JWT_SIGNATURES_SECRET_GENERATOR_SECRET to GENERATOR_SECRET didn't seems to work. I think that we had some problems with the kubernets pod configuration that keep the old var setted.

@jameskleeh
Copy link
Contributor

I have improved the error message, however without an example that reproduces the issue of the config being null, I don't know what to do there. If there is an issue, it would likely be in core as this library is reading config in a standard way.

@ronhitchens
Copy link

ronhitchens commented Apr 29, 2020

I did some experimentation with this yesterday and can reliably and easily reproduce this problem. It basically boils down to the fact that specifying the property via an environment variable doesn't work. There's also an issue that not specifying the signing secret does not cause a startup failure.

Without the workaround bean above in place, I tried the four combinations, defining the property in the application.xml file and in the environment variable MICRONAUT_SECURITY_TOKEN_JWT_SIGNATURES_SECRET_GENERATOR_SECRET. I also set a breakpoint in the constructor of SecretSignature to see the value of config that is passed in. I'm doing this from memory, but I think it's right.

  • application.yaml only: Worked as expected. SecretSignature is instantiated once and the parameter config has the expected value.
  • application.yaml and env var: Fails. SecretSignature is instantiated twice. The first time it is passed the value from the env var. The second time, the config parameter has a null value for secret. The NPE exception is subsequently throw in MACProvider.
  • Env var only: Fails in the same way as when both are defined. First instantiation has the value from the env var, then null on the second instantiation. Also throws the exception.
  • Not defined in either: Appears to work, but SecretSignature is never instantiated. No NPE exception is thrown, but logins never succeed. I didn't trace to see if it's actually contacting Auth0, or just short-circuiting and returning an Unauthorized.

The config we had was the second, the secret defined in the env with a fallback in application.xml. Frankly, I don't know how it ever worked. There must be a race in the property resolution where the instantiations sometimes happen in the opposite order. I did all this testing in my IDE (IntelliJ). Also, during development I never defined this property in the environment, which would explain why I never saw it until deployed in Amazon.

It's worrying that startup is not aborted when this critical property is not defined. This leads to mysterious and inexplicable behavior that's very hard to debug. I'm guessing that a @Requires annotation or something similar is needed.

The workaround bean is working fine for me. I discovered that with it in scope, and GENERATOR_SECRET not defined, that Micronaut refuses to startup saying that it could not inject the bean. That's the behavior I'd expect to see if the standard property was not defined.

I added an additional check to your workaround bean, just FYI

@Context
@Named("generator")
class GeneratorSecretSignature extends SecretSignature
{
	GeneratorSecretSignature (@Property(name = "generator.secret") String secret) {
		super (createSecretConfig (secret))
	}

	private static SecretSignatureConfiguration createSecretConfig (String secret) {
		if (secret && (secret.length() > 32)) {
			SecretSignatureConfiguration config = new SecretSignatureConfiguration ("generator")

			config.setSecret (secret)

			config
		} else {
			throw new ConfigurationException ("JWT signing secret is empty or less than 256 bits: ${secret}")
		}
	}
}

Please let me know if you need any further information from me.

Cheers.

@graemerocher
Copy link
Contributor

Thanks for the comprehensive feedback. @jameskleeh the change we should make is to initialize the config early and add validation to fail fast. This should be done for all security related configuration IMO.

@jameskleeh
Copy link
Contributor

If the secret is null it will now fail on application startup

@graemerocher
Copy link
Contributor

@jameskleeh can you reference the commit with the change?

@jameskleeh
Copy link
Contributor

@dgbmariano
Copy link

Thanks for the workaround. I made some testing and made a Koltin variation of the code written by @ronhitchens and now is working. Probably I was facing some problems with the environment variables.

@ecmel
Copy link

ecmel commented Sep 20, 2021

Still having a similar issue with AWS cognito and micronaut. It happens when I restart the application or upload a new version to the server.

{
    "message": "Internal Server Error",
    "_links": {
        "self": {
            "href": "/",
            "templated": false
        }
    },
    "_embedded": {
        "errors": [
            {
                "message": "Internal Server Error: Error instantiating bean of type  [io.micronaut.security.token.jwt.validator.JwtTokenValidator]\n\nMessage: Read Timeout\nPath Taken: new SecurityFilter(Collection securityRules,Collection authenticationFetchers,SecurityConfiguration securityConfiguration) --> new SecurityFilter(Collection securityRules,[Collection authenticationFetchers],SecurityConfiguration securityConfiguration) --> new TokenAuthenticationFetcher([Collection tokenValidators],TokenResolver tokenResolver,ApplicationEventPublisher eventPublisher) --> new JwtTokenValidator([Collection signatureConfigurations],Collection encryptionConfigurations,Collection genericJwtClaimsValidators,JwtAuthenticationFactory jwtAuthenticationFactory)"
            }
        ]
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants