{"record":{"id":"09e14c4110ec2088","repo":"Freika/dawarich","slug":"blank-token-09e14c","errorCode":null,"errorMessage":"blank token","messagePattern":"blank token","errorType":"exception","errorClass":"Auth::VerifyGoogleToken::InvalidToken","httpStatus":401,"severity":"error","filePath":"app/services/auth/verify_google_token.rb","lineNumber":13,"sourceCode":"# frozen_string_literal: true\n\nmodule Auth\n  class VerifyGoogleToken\n    class InvalidToken < StandardError; end\n\n    def initialize(id_token, nonce: nil)\n      @id_token = id_token\n      @nonce = nonce\n    end\n\n    def call\n      raise InvalidToken, 'blank token' if @id_token.blank?\n\n      client_ids = [\n        ENV['GOOGLE_IOS_CLIENT_ID'],\n        ENV['GOOGLE_ANDROID_CLIENT_ID'],\n        ENV['GOOGLE_OAUTH_CLIENT_ID']\n      ].compact\n      raise InvalidToken, 'Google client IDs not configured' if client_ids.empty?\n\n      validator = GoogleIDToken::Validator.new\n      claims = nil\n      audience_error = nil\n\n      client_ids.each do |client_id|\n        claims = validator.check(@id_token, client_id)\n        break if claims\n      rescue GoogleIDToken::AudienceMismatchError => e\n        audience_error = e\n        next","sourceCodeStart":1,"sourceCodeEnd":31,"githubUrl":"https://github.com/Freika/dawarich/blob/97fad417c5a11b0eb11157890635e015723a2e97/app/services/auth/verify_google_token.rb#L1-L31","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nresult = Auth::VerifyGoogleToken.new(params[:id_token]).call\n\n// after\nid_token = params[:id_token].to_s.strip\nif id_token.empty?\n  return render json: { error: 'id_token is required' }, status: :bad_request\nend\nresult = Auth::VerifyGoogleToken.new(id_token).call","handlingStrategy":"validation","validationCode":"id_token = params[:id_token].to_s.strip\nraise ActionController::ParameterMissing, 'id_token' if id_token.empty?","typeGuard":"def valid_id_token?(token) = token.is_a?(String) && !token.strip.empty?","tryCatchPattern":"begin\n  claims = Auth::VerifyGoogleToken.new(id_token).call\nrescue Auth::VerifyGoogleToken::InvalidToken => e\n  render json: { error: e.message }, status: :unauthorized\nend","preventionTips":["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."],"tags":["authentication","google-sign-in","id-token","input-validation","ruby"],"backgroundTag":"missing-auth-token","analyzedSha":"97fad417c5a11b0eb11157890635e015723a2e97","analyzedAt":"2026-08-21T17:04:17.778Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}