stytchauth/stytch-java

Local authentication of Session JWT failing

Closed this issue · 6 comments

I've been following the line of thinking from the Java backend examples, more specifically on the authentication callback and then using the session JWT to authenticate.

The main change I did was an attempt to use the local authentication for the session JWT token (StytchClient.sessions.authenticateJwtCompletable), but this seems to fail.

Below is the Kotlin code that reproduces the problem, which essentially condenses what the /authenticate handler would do, along with an attempt to immediately use the session JWT token produced after the authenticate call.

// Get token from /authenticate?token=....
val token = "" // fetch from request param
val getSessionResponse = StytchClient.magicLinks
    .authenticateCompletable(AuthenticateRequest(token, null, null, null, 30))
    .get()
if (getSessionResponse is StytchResult.Error) {
    getSessionResponse.exception.printStackTrace()
    throw getSessionResponse.exception
}
val authenticateResponse: AuthenticateResponse = (getSessionResponse as StytchResult.Success<AuthenticateResponse>).value
val sessionJwt = authenticateResponse.sessionJwt

println("Successfully fetched Session JWT")

// Immediately try to use this JWT token with local authentication
val authResponse = StytchClient.sessions.authenticateJwtCompletable(sessionJwt, null).get()
if (authResponse is StytchResult.Error) {
    authResponse.exception.printStackTrace()
    throw authResponse.exception
}

The output here is the following:

Successfully fetched Session JWT
Critical(reason=JwtError(exception=org.jose4j.jwt.consumer.InvalidJwtException: JWT processing failed. Additional details: [[17] Unable to process JOSE object (cause: org.jose4j.lang.UnresolvableKeyException: Unable to find a suitable verification key for JWS w/ header {"alg":"RS256","kid":"jwk-test-5c19ec40-763b-4acb-83cb-3df5ab1122db","typ":"JWT"} from JWKs [] obtained from https://test.stytch.com/v1/sessions/jwks/project-test-2e23c481-fefe-47ae-b694-0281a6fcb547): JsonWebSignature{"alg":"RS256","kid":"jwk-test-5c19ec40-763b-4acb-83cb-3df5ab1122db","typ":"JWT"}->eyJhbGciOiJSUzI1NiIsImtpZCI6Imp3ay10ZXN0LTVjMTllYzQwLTc2M2ItNGFjYi04M2NiLTNkZjVhYjExMjJkYiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsicHJvamVjdC10ZXN0LTJlMjNjNDgxLWZlZmUtNDdhZS1iNjk0LTAyODFhNmZjYjU0NyIsImFwcCJdLCJleHAiOjE2OTY3ODU4OTAsImh0dHBzOi8vc3R5dGNoLmNvbS9zZXNzaW9uIjp7ImlkIjoic2Vzc2lvbi10ZXN0LWE3ZGNhZGU5LWJkY2ItNGZhMi04MWM2LTkwZDI3ZmEwYWJkOSIsInN0YXJ0ZWRfYXQiOiIyMDIzLTEwLTA4VDE3OjE5OjUwWiIsImxhc3RfYWNjZXNzZWRfYXQiOiIyMDIzLTEwLTA4VDE3OjE5OjUwWiIsImV4cGlyZXNfYXQiOiIyMDIzLTEwLTA4VDE3OjQ5OjUwWiIsImF0dHJpYnV0ZXMiOnsidXNlcl9hZ2VudCI6IiIsImlwX2FkZHJlc3MiOiIifSwiYXV0aGVudGljYXRpb25fZmFjdG9ycyI6W3sidHlwZSI6Im1hZ2ljX2xpbmsiLCJkZWxpdmVyeV9tZXRob2QiOiJlbWFpbCIsImxhc3RfYXV0aGVudGljYXRlZF9hdCI6IjIwMjMtMTAtMDhUMTc6MTk6NTBaIiwiZW1haWxfZmFjdG9yIjp7ImVtYWlsX2lkIjoiZW1haWwtdGVzdC04NDQ0ZTUwZS0yMDU4LTQyNmYtYmY0Yy00ZDE1OWM4MDY4ZmEiLCJlbWFpbF9hZGRyZXNzIjoiY29zQHJlc29sdXRlLndvcmtzIn19XX0sImlhdCI6MTY5Njc4NTU5MCwiaXNzIjoic3R5dGNoLmNvbS9wcm9qZWN0LXRlc3QtMmUyM2M0ODEtZmVmZS00N2FlLWI2OTQtMDI4MWE2ZmNiNTQ3IiwibmJmIjoxNjk2Nzg1NTkwLCJyb2xlIjoiVVNFUiIsInN1YiI6InVzZXItdGVzdC0wMDJjZGFjNC02NTNhLTQwMjAtOWYxZC1lN2FjMGIwZGRmNDAifQ.plOgezb0fAiz30bKgGk2E4YxWRJ_fGvybMFaZTIy2q4xwBhWB7Ch0pXwULIvJCcQoJXZYke-n1TmeDyOlqFLPSz_PmmmRsZPiaLOJoSGSyeW3ZDwUB6iD-R7clqgN9Bubu84ogOr3gDq-iYbC1S8v8LOlMJ01xG29ipBrPXzYV7OHigHLjdNQ7z1FYiCPVhzE_iZlKtkCLDBcbkUbgLMkD74QYQku50SGyIvGaNHVQ_m8PdqRFHWqy7km4fqZC1KIcuFp3TK-VVEqPmYiUdc5pzVHR5g6mwbB1nal9P152MrzO3B2LilHafrkBFZjmEd07SigRX0ReiNlZvGtISgew]), response=null)
        at com.stytch.java.consumer.api.sessions.SessionsImpl.authenticateJwtLocal(Sessions.kt:342)
        at com.stytch.java.consumer.api.sessions.Sessions$DefaultImpls.authenticateJwtLocal$default(Sessions.kt:165)
        at com.stytch.java.consumer.api.sessions.SessionsImpl$authenticateJwt$2.invokeSuspend(Sessions.kt:277)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

The main issue has something to do with fetching verification keys for the JWT header:

Unable to find a suitable verification key for JWS w/ header {"alg":"RS256","kid":"jwk-test-5c19ec40-763b-4acb-83cb-3df5ab1122db","typ":"JWT"}

Hi, thanks for filing this issue, and apologies for the delay.

It looks like this is an issue with how strict Java is about generating X.509 certificates, and our JWKs are missing a field or two. I've raised this issue with the appropriate team, and will update this when I know more about a fix.

Hi, I just wanted to check in on the progress of this and see if there's any ETA for a fix?

I will ping our backend team today and see where this is on their roadmap!

A developer has been assigned this ticket and will be taking a look at it this week

Hey @cosmin-marginean wanted to let you know that our backend devs just deployed a fix and this method should be working.

Thank you again for your patience, and let me know if it works for you!

Yes, this seems to work fine! Thank you so much!