Freika/dawarich · error · Auth::VerifyGoogleToken::InvalidToken
blank token
Error message
blank token
What it means
Raised by Auth::VerifyGoogleToken#call when the id_token passed to the service is nil or empty (ActiveSupport #blank? matches '', nil, and whitespace-only strings). The service deliberately fails fast before any network call to Google, because an empty token can never validate. It surfaces as Auth::VerifyGoogleToken::InvalidToken, a StandardError subclass the auth controller layer is expected to rescue.
Source
Thrown at app/services/auth/verify_google_token.rb:13
# frozen_string_literal: true
module Auth
class VerifyGoogleToken
class InvalidToken < StandardError; end
def initialize(id_token, nonce: nil)
@id_token = id_token
@nonce = nonce
end
def call
raise InvalidToken, 'blank token' if @id_token.blank?
client_ids = [
ENV['GOOGLE_IOS_CLIENT_ID'],
ENV['GOOGLE_ANDROID_CLIENT_ID'],
ENV['GOOGLE_OAUTH_CLIENT_ID']
].compact
raise InvalidToken, 'Google client IDs not configured' if client_ids.empty?
validator = GoogleIDToken::Validator.new
claims = nil
audience_error = nil
client_ids.each do |client_id|
claims = validator.check(@id_token, client_id)
break if claims
rescue GoogleIDToken::AudienceMismatchError => e
audience_error = e
nextView on GitHub (pinned to 97fad417c5)
Solutions
- Log/inspect the incoming request params at the controller to confirm the token field is present and non-empty before invoking the service.
- Fix the client so it only submits after the Google SDK resolves with a real id_token (e.g. handle google.accounts.id cancel callbacks instead of posting on every click).
- If the parameter name differs, align it (params.require(:id_token) or the credential field) between client and server.
- In tests, pass a real-shaped (even if unsigned) JWT string so the service gets past the blank check.
Example fix
// before
result = Auth::VerifyGoogleToken.new(params[:id_token]).call
// after
id_token = params[:id_token].to_s.strip
if id_token.empty?
return render json: { error: 'id_token is required' }, status: :bad_request
end
result = Auth::VerifyGoogleToken.new(id_token).call Defensive patterns
Strategy: validation
Validate before calling
id_token = params[:id_token].to_s.strip raise ActionController::ParameterMissing, 'id_token' if id_token.empty?
Type guard
def valid_id_token?(token) = token.is_a?(String) && !token.strip.empty?
Try / catch
begin
claims = Auth::VerifyGoogleToken.new(id_token).call
rescue Auth::VerifyGoogleToken::InvalidToken => e
render json: { error: e.message }, status: :unauthorized
end Prevention
- Require the id_token param at the controller edge (params.require) so blanks never reach the service.
- On the client, only submit the sign-in form after the Google SDK resolves with a credential; disable submit while it is pending.
- Keep integration tests that assert a 400 (not 500) when the token field is omitted.
When it happens
Trigger: Calling Auth::VerifyGoogleToken.new(id_token).call with params[:id_token] missing from the request, a mobile client that sends an empty credential after a cancelled Google sign-in flow, or a form/JS client that posts before the Google SDK returns a token. Any whitespace-only string also triggers it.
Common situations: Frontend sends the field name the backend does not expect (credential vs id_token), Google One Tap / Sign-In SDK returns null on user dismissal and the caller forwards it anyway, integration tests that stub the UI but not the token payload.
Related errors
AI-assisted analysis of Freika/dawarich@97fad417c5 (2026-08-21).
Data as JSON: /api/errors/09e14c4110ec2088.
Report an issue: GitHub.