Reputation: 127
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
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
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