ai newsDi., 20. Okt.
EilmeldungNvidia, Dell back $200M round for AI model developer doubleAI

I stopped blaming GPT-5 for my Ads API 401 OAuth mess and fixed the 4 auth states that were actually broken

I lost a stupid amount of time blaming GPT-5 for an automation failure that had nothing to do with GPT-5. The setup looked normal enough: n8n pulls search term data from Google Ads GPT-5 classifies waste vs opportunity a review step approves changes the workflow pushes budget updates back Instead,

dev.toDienstag 00:09 · 20.10.7 Min. Lesezeit

Posted on Oct 19 • Originally published at standardcompute.com

I lost a stupid amount of time blaming GPT-5 for an automation failure that had nothing to do with GPT-5.

Instead, the job kept dying around 2 a.m. with a 401.

Then a Make scenario started failing on a Meta sync. Then a Python worker started returning invalid_grant. Then I did what a lot of us do when an "AI workflow" breaks:

Maybe GPT-5 was acting weird. Maybe Claude had generated a bad payload. Maybe the prompt had drifted. Maybe my routing logic was flaky.

The real problem was much more boring: auth.

And honestly, that's useful news, because auth failures are easier to fix than model behavior.

If you're running AI agents or automations against ad platforms, here's the thing I wish I'd internalized earlier:

Most Ads API 401s happen before your model, agent, or prompt ever gets a turn.

For Google Ads API, a valid access token is only part of the story.

You usually need all of these lined up at the same time:

Miss one, and your "AI failure" is really just a request getting rejected at the gate.

That login-customer-id detail is especially good at wasting afternoons.

If the authenticated identity is accessing a client account through a Google Ads manager account, you often need to send the manager account's 10-digit customer ID as login-customer-id.

Without it, the token can be valid and the request can still fail.

When I suspect a dead credential, I test refresh outside the app first:

curl -s -X POST https://oauth2.googleapis.com/token \ -d client_id = " $GOOGLE_CLIENT_ID " \ -d client_secret = " $GOOGLE_CLIENT_SECRET " \ -d refresh_token = " $GOOGLE_REFRESH_TOKEN " \ -d grant_type = refresh_token Enter fullscreen mode Exit fullscreen mode If this fails with invalid_grant, stop debugging your prompt.

{ "developer_token": "YOUR_DEVELOPER_TOKEN", "login_customer_id": "1234567890" } Enter fullscreen mode Exit fullscreen mode Example request header shape Authorization: Bearer ACCESS_TOKEN developer-token: YOUR_DEVELOPER_TOKEN login-customer-id: 1234567890 Enter fullscreen mode Exit fullscreen mode Not glamorous. But this is the layer that decides whether your agent runs at all.

A lot of teams treat Google refresh tokens like long-lived infrastructure. They are not.

Google refresh tokens can stop working for a bunch of reasons, including:

So you can build a workflow on Friday, watch it pass on Monday, and then spend the next week blaming GPT-5 for an auth lifecycle problem.

But the root cause was a 7-day refresh token timeout.

That's not an LLM issue. That's plumbing.

Because several different failures collapse into the same symptom.

A 401-looking Google Ads failure can mean:

This is why blind retries are mostly useless.

If the auth state is wrong, retries just burn time and make logs noisier.

The mental model that helped me was this:

Treat auth failures as state transitions, not transient errors.

Once I started doing that, the failures stopped feeling random.

Meta Marketing API gives you multiple token types, and a lot of overnight failures come from choosing the wrong one.

If your Make or Zapier scenario is using a short-lived user token for an unattended sync job, that is not AI unreliability.

That's just the wrong credential strategy.

For some Google Ads automations: yes, absolutely.

If the automation is server-side and operating on accounts your team already controls, service accounts are often the cleaner setup.

That second one matters more than people admit.

I've seen critical automations effectively authenticated as "someone from paid media who left three months ago." That's not architecture. That's a trap.

A Google service account does not automatically have Google Ads access.

You still have to add it inside the Google Ads UI.

Google Ads UI -> Admin -> Access and security -> Users -> + -> add service account email Enter fullscreen mode Exit fullscreen mode Then assign an appropriate role.

If you skip that step, the service account exists, the code looks fine, and the automation still fails.

Service accounts are not a universal answer.

You can't service-account your way out of delegated access.

I now use the same auth hardening rules whether the workflow runs in n8n, Make, a Python worker, or a Node service.

If your database column is just token_blob, you're making future-you miserable.

Don't wait for a live request to discover that auth is dead.

Refresh proactively when expiry is near.

from datetime import datetime, timedelta, timezone def should_refresh ( expires_at: datetime, buffer_minutes: int = 10 ) -> bool: now = datetime. now ( timezone. utc ) return now >= ( expires_at - timedelta ( minutes = buffer_minutes )) Enter fullscreen mode Exit fullscreen mode Move auth volatility out of the critical path.

This one causes a lot of fake mystery bugs.

If multiple workers try to refresh the same expired credential at once, they can stomp on each other:

Example with Redis-style locking pseudocode:

def refresh_with_lock ( credential_id ): lock_key = f " refresh-lock: { credential_id } " if not acquire_lock ( lock_key, ttl = 30 ): raise RuntimeError ( " refresh already in progress " ) try: credential = load_credential ( credential_id ) if not should_refresh ( credential. expires_at ): return credential new_token = refresh_token ( credential. refresh_token ) save_credential ( credential_id, new_token ) return new_token finally: release_lock ( lock_key ) Enter fullscreen mode Exit fullscreen mode One credential, one refresh path.

branch into auth recovery logic immediately.

What you should not do is retry the same broken state six times and call that resilience.

def call_ads_api ( request, credential ): response = send_request ( request, credential. access_token ) if response. status_code!= 401: return response refreshed = try_refresh ( credential ) if not refreshed: mark_reauth_required ( credential. id ) raise RuntimeError ( " reauth required " ) retry_response = send_request ( request, refreshed. access_token ) return retry_response Enter fullscreen mode Exit fullscreen mode My actual debugging checklist now When an ad automation fails, I check these in order:

1. Can the refresh token still mint a new access token? 2. Is the developer token present and valid? 3. Is login-customer-id required here? 4. Does the principal actually have access to the target customer account? 5. Is this tied to a user token that should really be a service account? 6. Is the OAuth app still in Testing mode? Enter fullscreen mode Exit fullscreen mode Meta 1. What token type is this? 2. Is it short-lived, long-lived, or system user? 3. Is this job unattended? 4. If yes, why am I still using a user token? Enter fullscreen mode Exit fullscreen mode Only after auth checks pass do I start looking at prompts, model routing, or agent behavior.

This matters even more when you're running agents continuously.

Once you have n8n flows, Make scenarios, Python workers, and scheduled jobs all calling APIs around the clock, per-request billing is not your only source of pain.

And when you're also paying per token for the model layer, bad auth hurts twice:

That's one reason I like using Standard Compute for agent and automation workloads. If I'm iterating on routing, retries, classification prompts, or recovery logic across GPT-5.4, Claude Opus 4.6, and Grok 4.20, I don't want token accounting to become part of the debugging stress.

Flat-rate, OpenAI-compatible compute is a much better fit for this kind of always-on workflow work than watching every model call like a taxi meter.

Especially when the real bug is often outside the model layer anyway.

We spend a lot of time comparing GPT-5, Claude, Grok, Qwen, Llama, routers, prompts, and agent frameworks.

But the smartest component in your stack is still downstream of the dumbest failure mode.

If Google Ads rejects the request because:

then the model never had a chance to succeed or fail.

Model problems can be slippery. Auth problems are usually concrete.

So if your ad automation keeps "mysteriously" dying, stop staring at GPT traces for a minute.

Check the credential type. Check the refresh lifecycle. Check whether the OAuth app is still in Testing. Check whether the principal actually has account access. Check login-customer-id.

Most of the pain is up there, before the agent ever runs.

Then your AI stack suddenly looks a lot smarter.

Quelle: dev.to (dev.to). Original öffnen