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​