Good timezone everyone! I do have a noob question ...
# kotlinx-rpc
m
Good timezone everyone! I do have a noob question here. context: I’m migrating my pet project from ktor http rest to kotlinx.rpc and I’m reaching a point where I’m not really sure how to continue. How can I handle Auth with rpc? right now I was jwt handling the headers and using the token of the requests to find the authenticated user but not sure how should/can I. handle it with RPC as i have the service abstraction but not directly the
RootingContext
where i can get the headers of… Any help is super welcome 🙏🏻
simples solution I can think of is passing the token to every service but not sure if this is something really nice… would ideally prefer to inject it once and forget about it like an interceptor or something
a
Hey! We don't have anything built-in right now, there was a discussion here https://github.com/Kotlin/kotlinx-rpc/issues/177
m
what would be then your recommendation on handling auth? (no real need on jwt, anything might work)
a
I would put main service under a Ktor authenticated route, and use a separate service for obtaining auth token which than can be put into RPC client headers.
🤘🏻 1
https://kotlin.github.io/kotlinx-rpc/transport.html#client here you can go
Copy code
ktorClient.rpc("<ws://localhost:4242/services>") { // this: HttpRequestBuilder
        headers["my-auth"] = "token"
    }
let me know if you encounter any issues
m
that looks cool, then i can just use any service to fetch the authenticated user. will try! thanks!
👍 1
for soem readon this last part doe snot sseem to add the header 🤔
Copy code
ktorClient.rpc("<ws://localhost:4242/services>") { // this: HttpRequestBuilder
        headers["my-auth"] = "token"
    }
now i understand the explanation but it still not solving my problem. If i have a service like so:
Copy code
@Rpc
interface TransactionsService : RemoteService {
    suspend fun getTransactrionList(): Flow<List<Transaction>>
}
and i would like to access the userId somehow how would I? right now I’m accessing it by reading the access token (I set the id in the
claim
) but as I don’t have access to the headers in the service I’m a bit lost on how can I identify the user 🤔
update: I actually realized the error happen on
Js
target. If i run jvm all looks good
a
@Marc can you share how you were able to get hold of the headers in your service implementation? I’m looking to do something similar, not for auth but to pass other context information down the chain
m
well I was not able with JS… for the other builds it’s just easy you can send them in the rpc/ws builder as its passes the
HttpRequestBuilder
as context
in the service then you just need to retrieve the principal you forwarded in the veryfy lamba of your authenticate:
Copy code
authentication {
    session<MySession> {
        validate { session ->
            session.also {
                println("session for: ${session.userId}")
            }
        }
    }
    jwt {
        realm = jwtRealm
        verifier(
            JWT
                .require(Algorithm.HMAC512(secret))
                .withClaimPresence("id")
                .withIssuer(issuer)
                .build(),
        )
        validate { credential ->
            println("claim id: ${credential.payload.getClaim("id")}")
            if (credential.payload.getClaim("id").asLong() != null) JWTPrincipal(credential.payload) else null
        }
    }
}
rpc("/api") {
    rpcConfig {
        serialization { json() }
    }
    val principal = call.principal<JWTPrincipal>()
    val userId = principal?.payload?.getClaim("id")?.let { UserId(it.asLong()) }
    print("userId is: $userId \n")
    print("payload is: ${principal?.payload} \n")

    userId?.run {
        registerService<TransactionsService> { context ->
            //UserId passed as context using context receivers
            TransactionsRpcService.new(coroutineContext = context)
        }
    }
}
🙏 1