Google credentials: which kind you need, and what breaks them
API key, OAuth client or service account, the seven-day trap in testing mode, the scopes to ask for, and what every common error actually means.
On this page
- What we'll cover
- Three ways in, and how to choose
- How the OAuth flow actually runs
- Creating the credential
- Internal, External, and the seven-day trap
- Building it with CodeWords
- Scopes, and asking for less
- Service accounts and the sharing step
- Token lifetimes and what revokes them
- The six errors and what each means
- Quotas, which are per user as well as per project
- Making it survive
- Limits worth knowing about
- What to decide first
- Frequently asked questions
- Related reading
Every automation touching Gmail, Sheets, Calendar or Drive starts at the same place, and most of the time lost is spent on one decision made wrongly at the beginning: which kind of credential the job actually needs. Pick the wrong one and you will spend an afternoon fighting consent screens for something a service account would have done in ten minutes, or the reverse.
After that, almost every failure is one of about six errors, each of which means something specific. This covers the choice, the setup, and what each error is telling you, including the seven-day expiry that catches nearly everybody once.
What we'll cover
- Three ways in, and how to choose
- How the OAuth flow actually runs
- Creating the credential
- Internal, External, and the seven-day trap
- Building it with CodeWords
- Scopes, and asking for less
- Service accounts and the sharing step
- Token lifetimes and what revokes them
- The six errors and what each means
- Quotas, which are per user as well as per project
- Making it survive
- Limits worth knowing about
- What to decide first
- Frequently asked questions
Three ways in, and how to choose
An API key identifies a project and nothing else. It works only for genuinely public data and cannot write anything. Most people who start here discover within an hour that they needed one of the others.
An OAuth client acts on behalf of a person, who approves the scopes on a consent screen. This is what you want when the data belongs to your users.
A service account is its own identity with its own email address and no human consent involved. It is for server-to-server work: a scheduled job processing a shared spreadsheet, a pipeline writing into a Drive folder.
The question that resolves it: whose data is it? If the answer is "a user's, and they need to agree", use an OAuth client. If it is "ours, and the job runs on a schedule", use a service account. If it is genuinely public and read-only, an API key will do.
How the OAuth flow actually runs
Four steps, and knowing them makes the errors legible.
- Your application redirects the user to Google's authorization endpoint, naming the scopes it wants.
- The user approves the consent screen. Google redirects back to your registered URI with an authorization code.
- Your application exchanges that code for an access token, valid for about an hour, and a refresh token, which lasts much longer.
- The access token goes on API calls. When it expires, the refresh token buys a new one without involving the user again.
The refresh token is the valuable part. It is what makes an automation run unattended, and its loss is what causes one to stop working weeks after anybody touched it.
Creating the credential
Create a project, ideally a dedicated one rather than sharing an existing project's quota and consent screen.
Enable the APIs you need. Gmail, Sheets, Drive, Calendar and YouTube are each enabled separately, and calls to a disabled API fail in a way that reads like a permissions problem.
Configure the consent screen, covered next because that choice matters more than it looks.
Create the credential. For an OAuth client, Web application for anything server-side with the redirect URI set exactly, Desktop for a local script. For a service account, create it and generate a key.
Keep the JSON out of version control. Add it to .gitignore before downloading rather than after, since a committed client secret means creating a new one.
Internal, External, and the seven-day trap
The consent screen has a user type and a publishing status, and together they produce the most common confusing failure in Google automation.
Internal is available to Google Workspace organisations and limits the app to users in that organisation. No verification needed, and it is the right choice for internal tooling.
External covers everybody else. While the publishing status is Testing, only listed test users can authorize, and the refresh tokens issued expire after seven days unless the only scopes requested are a subset of name, email address and profile.
That seven-day expiry is the trap. Everything works, and the following week the automation fails with invalid_grant for no apparent reason. Nothing changed; the token aged out because the app was still in Testing.
The fix is to move the app to In Production. Sensitive and restricted scopes require Google's verification review before that, which takes time, so it is worth starting early rather than discovering it the week you planned to launch (Google's OAuth documentation).
Building it with CodeWords
CodeWords connects to more than 3,000 integrations, and the connection is made once and reused.
- Open CodeWords and start a new automation.
- Describe what should happen in plain language to Cody, the automation builder, including which Google services are involved and whether the data belongs to a user or to the business.
- Authorize the Google connection once. Tokens are held and refreshed for you, and injected at run time rather than living in your code.
- Describe the exceptions, including what should happen when an authorization is revoked, since that is the failure that will eventually occur.
- Reuse the same connection across automations rather than creating a credential per workflow, which is where credential sprawl starts.
You describe the outcome; Cody builds it, connects it, and deploys it. The free plan covers light use, with Pro at $39 per month and Business at $100 per month as usage grows; details are on the pricing page.
Scopes, and asking for less
Scopes are the permissions attached to a token, and the instinct to request broad ones creates two problems: users decline more often, and the sensitive and restricted tiers pull you into a verification review you could have avoided.
Common combinations worth knowing:
spreadsheets.readonlyfor reading a sheet,spreadsheetsfor read and writedrive.filefor access limited to files your application created, which is far narrower thandriveand sufficient more often than people expectgmail.readonlyfor monitoring,gmail.sendfor sending,gmail.modifyfor labelling and organisingcalendar.eventsfor managing events without full calendar accessdriveonly when you genuinely need to see everything
Start with the narrowest that works. Widening later costs one re-consent; starting broad can cost a verification review.
Service accounts and the sharing step
The step that catches everybody: a service account cannot see a user's file simply because it exists in the same organisation.
A service account has its own email address, in the form name@project.iam.gserviceaccount.com. To let it read or write a spreadsheet or a Drive folder, that file must be shared with that email address, exactly as you would share with a colleague. Without it, every call returns a permission error that reads as though the credential is wrong when the credential is fine.
Two related points. Domain-wide delegation lets a service account impersonate users across a Workspace domain, which is powerful and worth restricting to the narrowest scopes. And service account keys do not expire, so a leaked one stays valid until somebody revokes it.
Token lifetimes and what revokes them
Access tokens last about an hour. Nothing to manage if your library refreshes them.
Refresh tokens in production do not expire on a timer, and they are revoked when the user removes your app's access, when their password changes in some Workspace configurations, when the scopes change, or when the token has gone unused for around six months.
That last one matters for anything seasonal. An automation that runs once a year will find its token revoked before its second run, and the fix is either to exercise it periodically or to expect a re-consent.
Refresh tokens in Testing expire after seven days, as above.
So treat re-authorization as a normal event rather than an incident: detect the failure, alert somebody, and document the re-consent process before you need it.
The six errors and what each means
redirect_uri_mismatch. The URI in your request is not in the Authorized Redirect URIs list. It is character-exact, including the protocol, port and trailing slash. Copy the URI out of the error and paste it in.
access_denied. The user refused, or the app is in Testing and they are not on the test users list.
invalid_grant. The refresh token is no longer valid. Testing-mode seven-day expiry, six months unused, a password change, or the user revoking access. Re-run the consent flow.
insufficient_scope or 403 insufficientPermissions. The token is valid and does not carry the scope for what you attempted. Add the scope and re-authorize; adding it without re-consenting changes nothing.
accessNotConfigured. The API is not enabled on the project. Enable it and allow a short propagation delay.
invalid_client. The client id or secret is wrong, usually because credentials from a different project got mixed in.
Quotas, which are per user as well as per project
Rate limits here are two-dimensional and people usually plan for only one.
The Sheets API, for instance, is limited per project and also per user per project, and the per-user limit is the one a single busy automation runs into first. A job hammering one account will be throttled long before the project quota is anywhere near.
Three practical responses: batch writes rather than one request per row, back off exponentially on a 429, and spread work across accounts where the design allows. Quotas are per API, so check the specific one.
Making it survive
One project per automation, so quota and consent settings do not interfere.
Move to In Production before you rely on it, and start verification early if your scopes need it.
Keep the client secret and any service account key out of the repository, and rotate keys on a schedule.
Alert on authorization failure rather than discovering it from a silent gap in the data.
Record which credential each automation uses, since credential sprawl is what makes a rotation frightening.
Limits worth knowing about
An API key cannot write anything, and cannot read private data.
Service accounts see only what has been shared with them, regardless of organisation membership.
Sensitive and restricted scopes need verification, which takes time you have to plan for.
Refresh tokens are revocable, so any design treating authorization as permanent will eventually fail.
Quotas bind per user as well as per project, which is the limit a single automation hits first.
What to decide first
Whose data it is. A user's, needing their consent, means an OAuth client. Your own, running on a schedule, means a service account. Genuinely public and read-only means an API key. Almost every painful Google credential afternoon starts with that question being answered wrongly and the setup being redone.
Two habits make the difference. Move the app out of Testing before you depend on it, because the seven-day refresh token expiry produces a failure a week later that looks like anything except what it is. And ask for the narrowest scope that works, since widening later costs one re-consent while starting broad can cost a verification review.
Frequently asked questions
Which Google credential type do I need?
Ask whose data it is. A user's, with their consent, means an OAuth client. Your own, running unattended, means a service account. Genuinely public and read-only means an API key.
Why did my automation stop working after a week?
The app is almost certainly still in Testing. External apps in Testing status issue refresh tokens that expire after seven days unless the only scopes are name, email and profile. Move to In Production.
What does invalid_grant mean?
The refresh token is no longer valid: the seven-day testing expiry, six months unused, a password change, or the user revoking access. Re-run the consent flow.
What causes redirect_uri_mismatch?
The redirect URI in the request is not in the Authorized Redirect URIs list, and the comparison is character-exact including protocol, port and trailing slash. Copy the URI from the error message.
Why can my service account not see the spreadsheet?
Because nobody shared it with the service account's email address. A service account is a separate identity and has no access to a file just by existing in the same organisation.
How long do access tokens last?
About an hour. Refresh tokens last far longer in production, and are revoked by user action, scope changes, some password changes, or roughly six months of disuse.
Which scopes should I request?
The narrowest that work. drive.file rather than drive, spreadsheets.readonly rather than spreadsheets, gmail.send rather than full mailbox access. Broad and sensitive scopes trigger a verification review.
Do service account keys expire?
No, which means a leaked key stays valid until somebody revokes it. Rotate them on a schedule and keep them out of version control.
Why am I being rate limited when I am well under the quota?
Quotas apply per user as well as per project, and the per-user limit is what a single busy automation reaches first. Batch requests, back off on a 429, and check the specific API's limits.