LW IT Solutions
« Blog Overview /Digital Marketing / Google Ads API Passkey Requirement: What It...
This post in other languages:

Google Ads API Passkey Requirement: What It Applies To and How to Find Forgotten Authorizations

Google Ads API Passkey Requirement: What It Applies To and How to Find Forgotten Authorizations
Contents
  1. 1. The login is in scope, the OAuth client is not
  2. 2. Write down who authorizes what
  3. 3. Find the forgotten authorizations
  4. 4. The emergency path for shared and agency access
  5. 5. Summary
  6. Sources

Google announced the passkey requirement for Google Ads API access on 27 July 2026, and the rollout began on 5 August. Since then the recurring question in every team chat has been some version of “do we have to reissue our OAuth client?” No. The requirement applies to how the user account behind an authorization signs in. The OAuth client is not the subject of this change, and existing tokens stay valid, so nothing stops working in the meantime. What the situation calls for is not a panic migration but an honest inventory of which integrations depend on a human being able to log in.

1. The login is in scope, the OAuth client is not

The distinction is narrow and it decides everything else. If an integration was authorized by a person clicking through a consent screen with their own Google account, that account’s sign-in falls under the passkey requirement. If it runs through a service account, it does not: service accounts are exempt. Same API, same client library, same customer IDs; the only difference is who authenticated.

Two things follow. No dashboard goes dark on a fixed date: existing tokens keep working, so the pressure point is the next time someone has to sign in, after a token is revoked by accident or a machine is rebuilt. And the risk sits in people, not in code. No repository records who holds the refresh token.

One correction, because it keeps circulating: several write-ups claim there is a seven-day lockout period for affected accounts. That is not in the announcement. There is no such deadline, and a migration plan built on it rushes the wrong work.

Two paths into a checkpoint: an integration authorised by a personal account must pass the passkey requirement, while a service account bypasses it
The requirement lands on the account that authorised the integration, not on the OAuth client. Everything wired through a service account walks past the checkpoint; everything wired through a person does not.

2. Write down who authorizes what

Start with the artefact almost nobody has: a written matrix of the access itself. A YAML file in the repository is a start, but a small SQLite table is better, because it will need querying. The columns that matter are the ones nobody can reconstruct from memory six months from now.

create table ads_authorization (
  integration     text primary key,
  auth_type       text not null check (auth_type in ('user_account','service_account')),
  google_account  text,
  config_path     text,
  token_store     text,
  owner           text not null,
  deputy          text,
  customer_ids    text,
  last_verified   date
);

insert into ads_authorization values
 ('nightly-cost-load','user_account','ads-bot@example.com','/srv/etl/conf/ads.yaml',
  'vault:kv/ads/refresh','l.wojcik','m.kowalski','123-456-7890,222-333-4444','2026-08-08'),
 ('bi-connector','service_account',null,'/srv/bi/sa.json',
  'gcp-secret-manager','platform-team',null,'123-456-7890','2026-08-08');
  • auth_type: splits the estate into in scope and out of scope with a single where clause.
  • deputy: the field this requirement is really about. If the person in owner is away for three weeks, who signs in?
  • token_store: a personal home directory here is a finding, not a value.

3. Find the forgotten authorizations

An inventory is only as good as its coverage, and the forgotten entries are the ones that hurt. Sweep the config trees, then compare the result against the written record.

grep -rIls -e refresh_token --include='*.y*ml' --include='*.json' --include='*.env' \
  /etc /srv /opt /home
#!/usr/bin/env python3
"""Classify local OAuth configs and diff them against the access inventory."""
import pathlib, re, sqlite3, sys

root = pathlib.Path(sys.argv[1])
patterns = ("*.yaml", "*.yml", "*.json", "*.env", "*.ini")
has_refresh = re.compile(r"refresh_token\s*[:=]\s*\S")
is_service = re.compile(r"service_account|private_key_id")

db = sqlite3.connect("access.db")
known = {row[0] for row in db.execute("select config_path from ads_authorization")}

for pattern in patterns:
    for path in sorted(root.rglob(pattern)):
        text = path.read_text(errors="ignore")
        if not (has_refresh.search(text) or is_service.search(text)):
            continue
        kind = "service_account" if is_service.search(text) else "user_account"
        flag = "" if str(path) in known else "  UNTRACKED"
        print(f"{kind:16}{path}{flag}")

Run it on every host that talks to the API, including the analyst laptop nobody wants to mention. Each UNTRACKED line is either a row missing from the inventory or a credential to revoke today. Each user_account line is a person who now has to be named.

4. The emergency path for shared and agency access

Now the operational part. For every user_account row, decide in advance what happens when that person is unavailable, because a sign-in that needs a passkey needs the human who holds it.

  1. Name a deputy with access to the same Google account under the applicable policy, and record them in the matrix.
  2. Move the refresh token out of personal files into the secret store, so re-authentication is the only step that still requires a person.
  3. Note per integration which customer IDs stop reporting if that authorization dies. That is the blast radius, and it sets the order of work.
  4. For agency setups, agree in writing which side holds the authorization and who is called on a Friday evening. Then check whether a service account is workable there, since those rows leave the scope of the requirement entirely.
select integration, google_account, owner, customer_ids
from ads_authorization
where auth_type = 'user_account'
  and (deputy is null or last_verified < date('now','-90 day'))
order by owner;

Put that query in a quarterly cron job and have it mail the output to the team. An empty result set is the whole review.

5. Summary

Three small things came out of this: a table that records which integration is authorized by which account, a sweep that finds the configurations nobody wrote down, and a query that lists every single point of failure with no deputy. None of it is specific to Google. It answers a question that every API with a human in the authorization chain eventually raises.

The gain is calm. Existing tokens keep working, service accounts are exempt, the OAuth client is untouched, and the seven-day lockout the forums keep repeating is not in the announcement at all. Read the original before acting on any summary, including this one: Passkey authentication requirement for the Google Ads API. Then spend the time saved on the rows in the matrix where deputy is still empty.

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

2 comments

  1. Niamh Hartigan

    The correction about the seven-day figure is the most valuable paragraph here — that number reached us through a vendor summary and was already in a migration plan.

    On the inventory itself: the config sweep finds files, but not the person behind an authorisation. How is that half established without interviewing everyone?

    1. Lukas Wojcik Author

      From the platform side, which is the half the repository genuinely cannot answer.

      Two sources cover most of it. The account’s own list of third-party applications shows which OAuth clients a person has authorised — that maps a human to a set of integrations without asking them. And the change history in the advertising account attributes API-driven changes to the account that made them, which connects a running job to a named person even when nobody remembers setting it up.

      Between those two and the file sweep the picture usually closes: files say what exists, the consent list says who authorised it, the change history says what it is still doing. The remainder — an integration whose token works but whose owner has left — is exactly the row the inventory exists to surface, and it is worth revoking rather than researching.

Write a comment

The email address is not published. Required fields are marked with an asterisk.

ALL ARTICLES & CATEGORIES

CCTV

Follow this category by RSS

Cloud & AI

Follow this category by RSS

Data Privacy

All 11 articles in this category Follow this category by RSS

Digital Analytics

All 44 articles in this category Follow this category by RSS

Digital Marketing

All 25 articles in this category Follow this category by RSS

IT & Networks

All 15 articles in this category Follow this category by RSS

Raspberry PI

Follow this category by RSS

Smart Home

All 11 articles in this category Follow this category by RSS

Web Development

Follow this category by RSS

WordPress Plugins & Tricks

Follow this category by RSS