Build a Custom Button
Google’s button is drawn in an iframe, so its props
are the only way to change it. For a button in your own design, use one of
Google’s OAuth2 flows behind your own <button>:
useTokenClient, the token model: Google gives the browser an access token.useCodeClient, the code model: Google gives the browser a code, which your server exchanges for tokens.
Neither gives the browser an ID token, so finding out who signed in takes one more step on your server, described below. If all you need is sign-in, Google’s button is less work.
With useTokenClient
Section titled “With useTokenClient”Both composables return isReady and login:
isReadyis a ref that turnstrueonce Google’s script has loaded and the client is ready. Disable your button until then.login()opens Google’s popup. Call it from a click, or the browser blocks the popup.
The example below also disables the button while the popup is open. If the
user closes the popup, or the browser blocks it, onNonOAuthError re-enables
it.
<script setup lang="ts">import { ref } from "vue";import { useTokenClient, type TokenClientSuccessResponse, type TokenClientErrorResponse,} from "vue3-google-signin";
const pending = ref(false);
const handleOnSuccess = (response: TokenClientSuccessResponse) => { pending.value = false; console.log("Access Token: ", response.access_token);};
const handleOnError = (errorResponse: TokenClientErrorResponse) => { pending.value = false; console.log("Error: ", errorResponse);};
const { isReady, login } = useTokenClient({ onSuccess: handleOnSuccess, onError: handleOnError, // The user closed the popup, or it was blocked onNonOAuthError: () => (pending.value = false), // other options});
const signIn = () => { pending.value = true; login();};</script>
<template> <button :disabled="!isReady || pending" @click="signIn"> Sign in with Google </button></template>The access token is ready to call Google APIs from the browser: Call Google APIs shows how to ask for scopes, check what the user granted and handle expiry.
With useCodeClient
Section titled “With useCodeClient”Usage is the same. onSuccess receives a code, which you post to your server
with an X-Requested-With header:
<script setup lang="ts">import { useCodeClient, type CodeClientSuccessResponse, type CodeClientErrorResponse,} from "vue3-google-signin";
const handleOnSuccess = async (response: CodeClientSuccessResponse) => { // Send the code to your server, which exchanges it for tokens await fetch("/api/google/connect", { method: "POST", headers: { "Content-Type": "application/json", // Google asks your server to check this header in popup mode "X-Requested-With": "XmlHttpRequest", }, body: JSON.stringify({ code: response.code }), });};
const handleOnError = (errorResponse: CodeClientErrorResponse) => { console.log("Error: ", errorResponse);};
const { isReady, login } = useCodeClient({ onSuccess: handleOnSuccess, onError: handleOnError, // other options});</script>
<template> <button :disabled="!isReady" @click="() => login()"> Sign in with Google </button></template>Your server exchanges the code for an access token and a refresh token with your client secret. Call Google APIs has the server code for Express and for a Nuxt server route.
Find out who signed in
Section titled “Find out who signed in”- With a code, the exchange on your server also returns
tokens.id_token, becauseopenidis always requested. Check it withverifyIdTokenas in Verify users on your server. - With an access token, send it to your server, which asks Google about it.
getTokenInfofrom google-auth-library returns the user’ssuband email, andaud, the client ID the token was issued for. Check thataudis your client ID, or a token issued to another app would sign someone in:
import { OAuth2Client } from "google-auth-library";
const google = new OAuth2Client();
const info = await google.getTokenInfo(accessToken);if (info.aud !== process.env.GOOGLE_CLIENT_ID) throw new Error("Wrong client");// info.sub is the user's Google account ID, info.email their email addressPre-select the account
Section titled “Pre-select the account”Both composables pass Google’s options through:
login_hint: the user’s email address orsub, to skip the account chooser for a user you already know.hd: limit the chooser to a Google Workspace domain.select_account: true(code client) orlogin({ prompt: "select_account" })(token client): always show the account chooser, for “Use another account”.