Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

New Google Sign-In API - refresh token

Problem

I am trying to use the New Google Sign-In API for authenticating with my own backend server. Every call to my server contains the idToken jwt as a Bearer token. On the backend side, I validate the token by checking the signature, and checking if the token is expired or not. The problem is that the New Google Sign-In API returns jwts with 1 hour expiration time, but I could not find any way to refresh the token.

Questions

  1. Is this a valid/safe way to authenticate the user with my backend server?
  2. How do I get a fresh id token without the user having to go through the sign-in flow again?

Code

How I get the idToken client side

fun showSignInDialog() {
  val request = GetSignInIntentRequest.builder()
    .setServerClientId(GOOGLE_SERVER_CLIENT_ID)
    .build()

  Identity.getSignInClient(context)
    .getSignInIntent(request)
    .addOnSuccessListener {
      googleSignInLauncher.launch(IntentSenderRequest.Builder(it).build())
    }
}

fun handleSignInResult(result: ActivityResult) {
  val credential = Identity.getSignInClient(context)
    .getSignInCredentialFromIntent(result.data)

  // later this token will be used for querying user-related data on my backend
  setToken(credential.googleIdToken)
}

How I validate my endpoints on the backend side

fun Application.installAuthentication() {
  val googleJwtIssuer = environment.config.property("jwt.google.domain").getString()
  val googleJwtAudience = environment.config.property("jwt.google.audience").getString()
  val jwtRealm = environment.config.property("jwt.google.realm").getString()
  val googleJwkProvider = JwkProviderBuilder(URL("https://www.googleapis.com/oauth2/v3/certs"))
    .cached(10, 24, TimeUnit.HOURS)
    .rateLimited(10, 1, TimeUnit.MINUTES)
    .build()
  install(Authentication) {
    jwt("google") {
      verifier(googleJwkProvider) {
        withIssuer(googleJwtIssuer)
        withAudience(googleJwtAudience)
      }
      realm = jwtRealm
      validate { credentials ->
        if (credentials.payload.audience.contains(googleJwtAudience))
          JWTPrincipal(credentials.payload)
        else
          null
      }
    }
  }
}

// in my main
installAuthentication()
routing {
  authenticate("google") {
    get("/get-todos") {
      val payload = call.principal<JWTPrincipal>()?.payload ?: error("JWTPrincipal not found")
      
      call.respond(getTodos(payload.subject))
    }
  }
}

Edit

Sample JWT returned by the google sign in API (on first sign in)

{
  "iss": "https://accounts.google.com",
  "azp": "secret",
  "aud": "secret",
  "sub": "secret",
  "email": "[email protected]",
  "email_verified": true,
  "name": "Ben Jerry",
  "picture": "https://lh3.googleusercontent.com/secret",
  "given_name": "Patrik",
  "family_name": "Aradi",
  "locale": "en-GB",
  "iat": 1616243551,
  "exp": 1616247151
}

It does not have a refresh token in it unfortunatelly

like image 379
A. Patrik Avatar asked Dec 19 '25 09:12

A. Patrik


1 Answers

I ended up using the old GoogleSignInApi's silent sign in feature for this. I've tested and if I use the New Google Sign In api for the sign in, the old one will still be able to perform the silent sign in.

It would be nice, if the new one had this silent sign in feature, but for now it looks like if you would like this "refresh" feature, you're still required to use the old api.

like image 136
A. Patrik Avatar answered Dec 21 '25 22:12

A. Patrik



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!