qwerfd
qwerfd

Reputation: 127

How to validate google access token inside of .net backend

Inside my frontend react app I get a token from google like this, using @react-oauth/google package

const googleLogin = useGoogleLogin({
    onSuccess: (response) =>
      requestExternalLogin("google", response.access_token),
    flow: "implicit",
  });

token response object example:

access_token: "ya29.a0AX9GBdUordgkAamV_nnKl3NEF6..."
authuser: "0"
expires_in: 3599
hd: "visma.com"
prompt: "none"
scope: "email profile openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email"
token_type: "Bearer"

I then pass that token to my .net backend and try to validate it like this:


var settings = new GoogleJsonWebSignature.ValidationSettings()
{
    Audience = new List<string>() { _googleConfig.GetSection("clientId").Value }
};

var payload = await GoogleJsonWebSignature.ValidateAsync(googleToken, settings);

but I keep getting an exception that says {"JWT must consist of Header, Payload, and Signature"}

Access token that I get from google should be a valid JWT that canbe used to get information from google's apis. Am I missing a step here?

Upvotes: 2

Views: 1717

Answers (2)

qwerfd
qwerfd

Reputation: 127

As mentioned in the selected answer, I was using the wrong kind of token. I needed id token, but the libraries either did not provide this token, or were using the old api. To use google's apis directly I ended up running this kind of setup:

useGoogleLogin hook

export function useGoogleLogin(
  btnRef: React.RefObject<HTMLDivElement>,
  loginCallback: (idToken: string) => void
) {
  const scriptCallback = () => {
    google.accounts.id.initialize({
      client_id: GOOGLE_OAUTH_CLIENT_ID,
      callback: (response) => loginCallback(response.credential),
    })

    google.accounts.id.renderButton(btnRef.current as HTMLElement, {
      theme: 'outline',
      size: 'large',
      type: 'standard',
    })
  }

  useEffect(() => {
    const src = 'https://accounts.google.com/gsi/client'
    const scriptId = 'gsi-client'

    loadScript(src, scriptId, scriptCallback)
  }, [])
}

loadScript function

const loadScript = (src: string, id: string, onload: () => void = () => {}) => {
  const existingScript = document.getElementById(id)

  if (existingScript != null) return

  const script = document.createElement('script')
  script.id = id
  script.src = src
  script.defer = true
  script.async = true
  script.onload = onload

  document.head.appendChild(script)
}

export default loadScript

And then just use it in your component like this:

const divRef = useRef(null)

useGoogleLogin(divRef, (idToken: string) => {
  //callback when user clicks the button
  //use this callback to send idToken to your backend or do something else
})

return <div ref={divRef} /> //your google login button

You also need to install @types/google.accounts, if you're running typescript

Upvotes: 1

Linda Lawton - DaImTo
Linda Lawton - DaImTo

Reputation: 117146

Google access tokens are not JWT's that can be validated in that manner. Try puting it in Jwt.io you will get the same error.

The only way to validate an google access token would be to use it with an api call if its not valid google will return an error.

You should be able to validate a refresh token though, and possibly an id token.

Upvotes: 1

Related Questions