Skip to main content

JWT Token Validation

OneTap Login validates every Google authentication using JWT (JSON Web Token) verification. This ensures only legitimate Google authentications are accepted.

What is JWT?

Definition

JWT (JSON Web Token) is an open standard (RFC 7519) for securely transmitting information between parties as a JSON object. Google uses JWTs for authentication tokens.

Structure

A JWT has three parts:

header.payload.signature

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwiYXVkIjoiMTIzNDUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTc4OTUiLCJlbWFpbCI6InVzZXJAZXhhbXBsZS5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNjE2MjM5MDIyLCJleHAiOjE2MTYyNDI2MjJ9.
[signature]

Decoded Payload

{
"iss": "accounts.google.com",
"azp": "12345.apps.googleusercontent.com",
"aud": "12345.apps.googleusercontent.com",
"sub": "117895234567890123456",
"email": "user@example.com",
"email_verified": true,
"name": "John Doe",
"given_name": "John",
"family_name": "Doe",
"picture": "https://lh3.googleusercontent.com/...",
"locale": "en",
"iat": 1616239022,
"exp": 1616242622
}

Validation Flow

Complete Flow

User completes Google sign-in

Google returns ID token (JWT)

OneTap sends to Google tokeninfo

Google validates signature

Valid → Returns payload

Invalid → Returns error

OneTap validates payload claims

All valid → Proceed

Any invalid → Reject

Validation Steps

StepCheckFailure Action
1Token presentReject
2Signature validReject
3Not expired (exp)Reject
4Correct issuer (iss)Reject
5Correct audience (aud)Reject
6Email verifiedReject
7Not too old (iat)Warn

Token Claims

Required Claims

ClaimDescriptionExpected Value
issIssueraccounts.google.com or https://accounts.google.com
audAudienceYour Client ID
subSubject (Google ID)Unique user ID
emailUser's emailValid email
email_verifiedEmail verificationtrue
expExpirationFuture timestamp
iatIssued atRecent timestamp

Optional Claims

ClaimDescriptionUsage
nameFull nameDisplay name
given_nameFirst nameFirst name field
family_nameLast nameLast name field
pictureAvatar URLProfile picture
localeLanguageUser locale
azpAuthorized partyAdditional verification

Validation Implementation

Google Token Verification

OneTap uses Google's tokeninfo endpoint:

// Token verification
$response = wp_remote_get(
'https://oauth2.googleapis.com/tokeninfo?id_token=' . $token
);

if (is_wp_error($response)) {
throw new Exception('Validation request failed');
}

$payload = json_decode(wp_remote_retrieve_body($response), true);

if (isset($payload['error'])) {
throw new Exception('Invalid token: ' . $payload['error']);
}

Audience Verification

// Check audience matches your Client ID
if ($payload['aud'] !== get_option('onetap_client_id')) {
throw new Exception('Token audience mismatch');
}

Issuer Verification

// Check issuer is Google
$valid_issuers = [
'accounts.google.com',
'https://accounts.google.com'
];

if (!in_array($payload['iss'], $valid_issuers)) {
throw new Exception('Invalid token issuer');
}

Email Verification

// Check email is verified by Google
if ($payload['email_verified'] !== true) {
throw new Exception('Email not verified by Google');
}

Expiration Check

// Check token not expired
if ($payload['exp'] < time()) {
throw new Exception('Token has expired');
}

Issued At Check

// Check token not too old (e.g., 10 minutes)
$max_age = 600; // 10 minutes
if ($payload['iat'] < (time() - $max_age)) {
// Warning: Token is old but may still be valid
// Depending on use case, may reject or proceed with caution
}

Security Considerations

Why Validate Server-Side?

Client-side validation is insufficient:

  • JavaScript can be modified
  • Tokens can be forged
  • Man-in-the-middle attacks

Server-side validation ensures:

  • Token authenticity
  • Signature verification
  • Claim accuracy

Token Handling

// Never log full tokens
error_log('Token received for: ' . $payload['email']);

// Never store tokens long-term
// Tokens are single-use

// Never send tokens to third parties
// Unless absolutely necessary with user consent

HTTPS Requirement

Token validation requires HTTPS:

  • Tokens in transit must be encrypted
  • HTTP would expose tokens to interception
  • Google rejects non-HTTPS for production

Common Validation Errors

Invalid Token

Error: Invalid token

Causes:

  • Token corrupted
  • Token modified
  • Wrong token type

Solution: Ensure complete token is sent unchanged.

Token Expired

Error: Token has expired

Causes:

  • User took too long to complete sign-in
  • Clock sync issues
  • Token replay attempt

Solution: Request new token; check server time.

Audience Mismatch

Error: Token audience mismatch

Causes:

  • Wrong Client ID configured
  • Token from different application
  • Configuration error

Solution: Verify Client ID in settings matches Google Cloud Console.

Invalid Issuer

Error: Invalid token issuer

Causes:

  • Token not from Google
  • Forged token
  • Wrong authentication provider

Solution: Ensure Google OAuth is properly configured.

Email Not Verified

Error: Email not verified by Google

Causes:

  • Google account email not verified
  • Very new Google account
  • Enterprise account without verification

Solution: User must verify email with Google first.

Debugging Token Issues

View Token Claims

For debugging (remove in production):

// Debug: View token payload
$payload = json_decode(
base64_decode(
str_replace(['-', '_'], ['+', '/'],
explode('.', $token)[1]
)
),
true
);
error_log('Token claims: ' . print_r($payload, true));

Check Token Manually

Use jwt.io (for debugging only):

  1. Go to https://jwt.io
  2. Paste token in debugger
  3. View decoded payload
  4. Never use production tokens!

Google OAuth Playground

Test tokens with Google's OAuth Playground:

  1. Go to https://developers.google.com/oauthplayground
  2. Select Google OAuth2 API
  3. Authorize
  4. Exchange code for tokens
  5. Examine token structure

Token Lifecycle

Creation

User clicks Google sign-in

Google authenticates user

Google creates JWT with:
├── User info claims
├── Audience (your app)
├── Expiration (usually 1 hour)
└── Signature (Google's key)

JWT sent to your site

Validation

JWT received by OneTap

Sent to Google tokeninfo

Google verifies signature

Returns payload or error

Expiration

Token valid for ~1 hour

After expiration:
├── Cannot be used
├── New sign-in required
└── Google issues new token

Best Practices

Do's

  • Always validate server-side
  • Check all required claims
  • Use HTTPS everywhere
  • Log validation failures
  • Monitor for anomalies

Don'ts

  • Trust client-side validation alone
  • Store tokens long-term
  • Log full token contents
  • Share tokens with third parties
  • Ignore validation errors

Hooks for Developers

After Token Validation

add_action('onetap_token_validated', function($payload) {
// Additional checks
error_log('Validated token for: ' . $payload['email']);

// Custom validation
if (custom_check_fails($payload)) {
throw new Exception('Custom validation failed');
}
}, 10, 1);

Filter Payload

add_filter('onetap_token_payload', function($payload) {
// Modify payload before use
// Use with caution!
return $payload;
});

Next Steps