I have trouble understanding how to do OAuth in my...
# ktor
s
I have trouble understanding how to do OAuth in my client. Following the sample from https://ktor.io/docs/auth.html I can get my user info once, but if I try to reuse the authorizationCode I get an
invalid_grant
I guess I need to save the accessToken, correct? Does someone have a demo how to do proper OAuth with Ktor?
h
is the oauth flow driven by the client, or the server?
h
afaik, the client does the login and send the created access token with every call through your api in ktor
s
why is the auth token invalid after that?
h
if you need the external ID you create the access token through your backend and save the issuer id from the encoded accesstoken to match your user with the external one
the auth token will be transformed into an accesstoken, which will be used from that moment on.
s
The Ktor sample is really bad unfortunately. It shows one-time usage. But what I want is auth the user once.
I'm not sure how to do that with Ktor 😕
h
correct, that is why this is an example of the complete process ;)
s
A realistic use case would be that I save the access token and provide it next time I build a Ktor client
h
you don’t save the access token on the server side, the handling always in the client
s
I have a app that should sync files with Google Drive. My users should login once into the Google account and after that they should stay authenticated
Now the auth token I get is only good for one session.
h
ok now I understand you, but still the same, only the first call uses the auth token. after that you use the access_token. and needed the refresh_token to generate a new access token

https://a.slack-edge.com/fbd3c/img/api/articles/oauth_scopes_tutorial/slack_oauth_flow_diagram.png

Ktor really lacks samples how to use it in a real world use case 😕
👍 1
h
what I recommend is to reuse the apiclient, till you get a 403/401 and ask the user to relogin from the beginning. the complete oauth flow is available in the example, nothing to change
and the apiclient can be reused as often you need
s
If the user closes the app the apiclient is gone
My app is a photo app that should sync with Google Drive in the background. It can be restarted. Users should only login once.
So I need to figure out how apiclient creation looks like for reuse
From the illustration I got the feeling that I need to store the access token and the refresh token in the client database
h
yes
s
Wouldn't I loose the automatic refresh token ability that way? 🤔
a
Sorry, this answer for the OAuth2 provider on the server. Since access and refresh tokens are stored in memory you can save them in some persistent storage. Here is an example:
Copy code
fun main() {
    val authClient = HttpClient(CIO)

    val client = HttpClient(CIO) {
        install(Auth) {
            lateinit var tokenInfo: TokenInfo

            bearer {
                loadTokens {
                    var token = getSavedToken()

                    if (token == null) {
                        token = authClient.requestToken()
                        // save token to database
                    }

                    BearerTokens(token.accessToken, token.refreshToken)
                }

                refreshTokens {
                    val info = authClient.refreshToken(tokenInfo.accessToken)
                    // save access token to database
                    BearerTokens(info.accessToken, tokenInfo.refreshToken)
                }
            }
        }
    }
}

data class TokenInfo(val accessToken: String, val refreshToken: String)

suspend fun HttpClient.requestToken(): TokenInfo {
    return TokenInfo("access", "refresh")
}

suspend fun HttpClient.refreshToken(accessToken: String): TokenInfo {
    return TokenInfo("access", "refresh")
}

suspend fun getSavedToken(): TokenInfo? {
    return TokenInfo("access", "refresh")
}
👍 1
🙏 1
s
Thanks, I'll test it. If it works this should be the official sample ^^