-
Notifications
You must be signed in to change notification settings - Fork 28
Authentication Reference
If you are new to GCPwn, read Getting Started first.
This page is the canonical authentication reference for GCPwn. It covers each auth mode, setup patterns, startup syntax, and in-workspace credential operations.
- Auth Modes at a Glance
- GCPwn Startup Commands
- After Startup
- Tokeninfo Quick Note
- Application Default Credentials (ADC)
- OAuth2 Token
- Service Account Key
- Auth Operational Notes
- Common Auth Errors
- Source References
| Auth Type | Supported in GCPwn | Typical Credential Source | Rotation Model | Common Use |
|---|---|---|---|---|
ADC (adc) |
Yes | Local Google auth defaults / ADC JSON | Refresh-token backed OAuth flow | Standard operator workflow with gcloud. Can result in OAuth2 tokens for next row being created, but has refresh mechanism backing. |
OAuth2 token (oauth2) |
Yes | Direct bearer token input | Short-lived bearer token | Testing standalone delegated/harvested access tokens identified (ex ya29.a0AfH6SM...) |
Service account key (service-acc-key / service) |
Yes | Service account JSON key file | Long-lived key unless rotated | Service-account identity operations |
At startup, add credentials with one of the following patterns:
adc
adc <credential_name> [--filepath-to-adc <adc_json_path>] [--tokeninfo]
oauth2
oauth2 <credential_name> --token <access_token> [--tokeninfo]
service-acc-key
service-acc-key <credential_name> --service-file <service_account_json_path>
Quick startup examples:
adc corp-adc --filepath-to-adc ~/.config/gcloud/application_default_credentials.json
oauth2 redteam-token --token ya29.a0AfH6SM...
service-acc-key app-sa --service-file /tmp/app-sa.json
You can also select an existing credential by name/index, or press Enter to continue without loading credentials.
creds listcreds swap [<credname>]creds info [<credname>] [--csv]creds tokeninfo [<credname>]creds update [<credname>] --type <adc|oauth2|service> [credential flags...] [--assume]
Add new credentials at startup (adc, oauth2, service-acc-key), then use creds update to refresh stored credentials.
For full workspace command coverage, see Workspace Instructions.
BOTH user and service account access tokens can exist, but the token string by itself does not clearly identify the principal behind it (you can't base64 decode it like a JWT; its "opaque").
The --tokeninfo flag and creds tokeninfo command call Google’s /tokeninfo endpoint to return token metadata (for example, email and scopes) given an access token. This helps enrich your session data, details who the token belongs to if you don't have that context, and maps the current credential to the correct IAM identity during enumeration.
Tokeninfo Endpoint
https://oauth2.googleapis.com/tokeninfo?access_token=<ACCESS_TOKEN>
GCPwn examples
# When adding creds
oauth2 redteam-token --token ya29.a0AfH6SM... --tokeninfo# While in workspace
creds tokeninfo redteam-tokenReferences
- https://docs.cloud.google.com/docs/authentication/token-types#user-access-tokens
- https://docs.cloud.google.com/docs/authentication/token-types#sa-access-tokens
Application Default Credentials (ADC) is not a single credential. It is Google’s credential discovery mechanism used by SDK-backed tooling to automatically locate usable auth material.
In GCPwn, this maps to google.auth.default() behavior. The library resolves the active credential source for you (local user ADC, service account material, workload identity config, or metadata-attached identity).
Common ADC lookup order in operator workflows as follows, so unset GOOGLE_APPLICATION_CREDENTIALS if that is potentially causing you issues as we focus on 2 for now:
-
GOOGLE_APPLICATION_CREDENTIALSenvironment variable - Local ADC file from
gcloud auth application-default login
If you are operating interactively, "ADC" usually maps to user-backed OAuth credentials (aka. username/password login) which is what we will consider here.
# Browser-based user auth + local ADC file
gcloud auth application-default login
# Recommended to avoid project-context confusion
gcloud config set project <project_ID>
# After starting gcpwn choose ADC as your option with your crednmae. Default ADC file location is usually ~/.config/gcloud/application_default_credentials.json but you can specify path to another file if needed
gcpwn> adc <credname> [--filepath-to-adc ~/.config/gcloud/application_default_credentials.json]| Field | Required | Source |
|---|---|---|
credential_name |
Yes | Operator-defined alias |
--filepath-to-adc |
No | ADC JSON file path |
--tokeninfo |
No | Query Google tokeninfo metadata endpoint |
-
gcloud auth login: authenticates thegcloudCLI user context. i.e. you can make furthergcloudcommands at command line as that user. -
gcloud auth application-default login: creates ADC material for SDK/client-library usage. i.e. you can make further SDK calls as the user you authenticated as
For GCPwn, application-default login is the key requirement because GCPwn relies on SDK-backed authentication resolution.
> gcloud auth application-default login
Your browser has been opened to visit:
https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=76408[REDACTED]Sign in through the browser flow:

After redirecting back to localhost, Google writes your ADC credential file under .config/gcloud:
Credentials saved to file: [/home/kali/.config/gcloud/application_default_credentials.json]
These credentials will be used by any library that requests Application Default Credentials (ADC).Inspect the file. Note there is a client_id, client_secret, and refresh_token. These can be ingested as we will see by a python SDK/code for GCP to auto gen a token and make subsequent API calls.
# cat /home/kali/.config/gcloud/application_default_credentials.json
{
"account": "",
"client_id": "764086[REDACTED].apps.googleusercontent.com",
"client_secret": "d-FL[REDACTED]",
"refresh_token": "1//01i[REDACTED]",
"type": "authorized_user",
"universe_domain": "googleapis.com"
}
The ADC file itself does not set your intended project target. Set project context explicitly to avoid issues with gcpwn:
# Set the project to avoid issues down the road
gcloud config set project <PROJECT_ID>
In the ADC file we saw a client_id, client_secret, refresh_token but no access token to send directly to a GCP API. You will typically see a refresh token, not a long-lived pre-generated access token.
At runtime, GCPwn loads the ADC material, uses the material to request and store an access token, uses that access token for subsequent calls, and reuses stored refresh material (ex. refresh_token) for future auto-refresh attempts when the token is invalid.
After startup, load ADC. Note this was successful and gcpwn in the background requested and stored an access token as we will see in the next step.
What you will notice is the final access token (ya29...) is opaque, or you can't decode it locally. Same with gpwn. If you want to decode the opaque access token to better enrich your data then run creds tokeninfo to inspect token metadata (email/scopes) from Google’s tokeninfo endpoint:
Welcome to your workspace! Type 'help' or '?' to see available commands.
[-] No creds found
Submit the name or index of an existing credential from above, or add NEW credentials via:
[1] adc <credential_name> [--filepath-to-adc <adc_json_path>] [--tokeninfo]
[2] oauth2 <credential_name> --token <access_token> [--tokeninfo]
[3] service-acc-key <credential_name> --service-file <service_account_json_path>
Tip: `--tokeninfo` queries Google's tokeninfo endpoint to capture scope/email for OAuth-style creds.
Input: adc starting_user_token
[*] Project ID of credentials is: <PROJECT_ID>
[*] Credentials successfully added
[*] Loading in ADC credentials...
[*] Attempting to refresh the credentials using the stored refresh token. Note this is normal for brand new OAuth2 credentials added/updated.
[*] Credentials successfully refreshed...
[*] Credentials successfully stored/updated...
[*] Proceeding with up-to-date ADC credentials for starting_user_token...
[*] Loaded credentials starting_user_token
(<PROJECT_ID>:starting_user_token)> creds tokeninfo
[*] Checking credentials against https://oauth2.googleapis.com/tokeninfo endpoint...
[*] Succeeded in querying tokeninfo. The response is shown below:
{
"azp": "764086[TRUNCATED]",
"aud": "764086[TRUNCATED]",
"sub": "1057[TRUNCATED]",
"scope": "email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.login https://www.googleapis.com/auth/userinfo.email openid",
"exp": "1778303317",
"expires_in": "3512",
"email": "[REDACTED_EMAIL]",
"email_verified": "true",
"access_type": "offline"
}
If you want to see the actual access token generated, you can inspect databases/sessions.db to confirm that GCPwn stored session credential material, including refreshed access-token state:
# sqlite3 databases/sessions.db
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .tables
session session_actions
sqlite> SELECT workspace_id, credname, credtype, email, default_project FROM session;
1|starting_user_token|adc|[REDACTED_EMAIL]|<PROJECT_ID>
Session credential payload (formatted):
{
"token": "ya29.a0AQvPyI[REDACTED]",
"refresh_token": "1//01in[REDACTED]",
"token_uri": "https://oauth2.googleapis.com/token",
"client_id": "76408[TRUNCATED]",
"client_secret": "d-FL[REDACTED]",
"universe_domain": "googleapis.com",
"account": "",
"expiry": "2026-05-09T05:08:36.410200Z"
}If needed, you can manually:
- exchange refresh token material for an access token
- send that access token to
/tokeninfo - Use that access token as a token input credential in gcpwn covered in the next section
Generate Access Token
# curl request
CLIENT_ID="<CLIENT_ID>"
CLIENT_SECRET="<CLIENT_SECRET>"
REFRESH_TOKEN="<REFRESH_TOKEN>"
curl -sS -X POST "https://oauth2.googleapis.com/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=${CLIENT_ID}" \
--data-urlencode "client_secret=${CLIENT_SECRET}" \
--data-urlencode "refresh_token=${REFRESH_TOKEN}" \
--data-urlencode "grant_type=refresh_token"
# curl example
CLIENT_ID="764[TRUNCATED]"
CLIENT_SECRET="d-FL[REDACTED]"
REFRESH_TOKEN="1//01i[REDACTED]"
curl -sS -X POST "https://oauth2.googleapis.com/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "client_id=${CLIENT_ID}" \
--data-urlencode "client_secret=${CLIENT_SECRET}" \
--data-urlencode "refresh_token=${REFRESH_TOKEN}" \
--data-urlencode "grant_type=refresh_token"
{
"access_token": "ya29.a0AQvPyIOFt[REDACTED]",
"expires_in": 3599,
"scope": "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/sqlservice.login openid https://www.googleapis.com/auth/cloud-platform",
"token_type": "Bearer",
"id_token": "eyJhbGciOiJSUz[REDACTE]"
} Send Token to /tokeninfo
# curl request
>curl "https://oauth2.googleapis.com/tokeninfo?access_token=<token>"
#example
> curl "https://oauth2.googleapis.com/tokeninfo?access_token=ya29.a0AQvPy[REDACTED]"
{
"azp": "7640[TRUNCATED].com",
"aud": "7640[TRUNCATED].com",
"sub": "1057[TRUNCATED]",
"scope": "email https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/sqlservice.login https://www.googleapis.com/auth/userinfo.email openid",
"exp": "1778303317",
"expires_in": "3188",
"email": "[REDACTED_EMAIL]",
"email_verified": "true",
"access_type": "offline"
}Like I showed before, gcpwn ALSO stores the refresh material from ADC. So if your access token expires and the tool doesn't auto-refresh it, or you want to refresh your token sooner, you can do that as shown below assuming your adc creds have not changed
(<PROJECT_ID>:starting_user_token)> creds update starting_user_token --type adc --assume
[*] Project ID of credentials is: <PROJECT_ID>
[*] Credentials successfully added
[*] Loading in ADC credentials...
[*] Attempting to refresh the credentials using the stored refresh token. Note this is normal for brand new OAuth2 credentials added/updated.
[*] Credentials successfully refreshed...
[*] Credentials successfully stored/updated...
[*] Proceeding with up-to-date ADC credentials for starting_user_token...
[*] Loaded credentials starting_user_token
OAuth2 tokens can come from multiple sources in GCP for both users and service accounts. They typically look like ya29.... These might be from a local user:<email> on the system or a serviceAccount:<email> attached to something like a compute instance for example (classic SSRF).
If you recover a standalone OAuth2 token, you can load it directly into GCPwn and begin making API calls immediately.
Important caveat: a standalone access token is short-lived and cannot be auto-refreshed by itself unless you also have refresh material. Review the instructions to refresh the <credname> at the end of this section
# Obtain a valid OAuth2 access token (ex. `ya29...`)
# Pass the token into GCPwn
oauth2 redteam-token --token ya29.a0AfH6SM...| Field | Required | Source |
|---|---|---|
credential_name |
Yes | Operator-defined alias |
--token |
Yes | OAuth2 bearer token |
--tokeninfo |
No | Query Google tokeninfo metadata endpoint |
There are a lot of paths that can lead to an OAuth token being recovered. Two common operator paths are:
- user token via
gcloud auth login(or recovered local gcloud token cache) - service-account token via instance metadata (IMDS)
Run login and complete browser auth:
# gcloud auth login
Your browser has been opened to visit:
https://accounts.google.com/o/oauth2/auth?response_type=code&client_id=3255[REDACTED]
You are now logged in as [REDACTED_EMAIL].
Your current project is [<PROJECT_ID>]. You can change this setting by running:
$ gcloud config set project PROJECT_IDgcloud auth login commonly creates/updates token stores under ~/.config/gcloud, including:
-
access_tokens.db(short-lived access tokens) -
credentials.db(credential profile material that may include refresh-backed fields)
$ ls -lart /home/kali/.config/gcloud/
total 72
[TRUNCATED]
-rw------- 1 kali kali 5 May 9 01:03 gce
-rw-r--r-- 1 kali kali 12288 May 9 01:03 default_configs.db
-rw------- 1 kali kali 12288 May 9 01:03 access_tokens.db
-rw------- 1 kali kali 12288 May 9 01:03 credentials.db
drwxrwxr-x 3 kali kali 4096 May 9 01:03 legacy_credentials
$ sqlite3 /home/kali/.config/gcloud/access_tokens.db
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> PRAGMA table_info(access_tokens);
0|account_id|TEXT|0||1
1|access_token|TEXT|0||0
2|token_expiry|TIMESTAMP|0||0
3|rapt_token|TEXT|0||0
4|id_token|TEXT|0||0
sqlite> SELECT * FROM access_tokens;
[REDACTED_EMAIL]|ya29.a0[TRUNCATED]|2026-05-09 06:03:55.997030||eyJhbG[TRUNCATED]
credentials.db can also contain refresh/token profile material:
$ sqlite3 /home/kali/.config/gcloud/credentials.db
SQLite version 3.46.1 2024-08-13 09:16:08
Enter ".help" for usage hints.
sqlite> .tables
credentials
sqlite> SELECT * FROM credentials;
[REDACTED_EMAIL]|{
"client_id": "32555940559.apps.googleusercontent.com",
"client_secret": "Zms[REDACTED]",
"refresh_token": "1//01p9Q[REDACTED]",
"revoke_uri": "https://oauth2.googleapis.com/revoke",
"scopes": [
"openid",
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/appengine.admin",
"https://www.googleapis.com/auth/sqlservice.login",
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/accounts.reauth"
],
"token_uri": "https://oauth2.googleapis.com/token",
"type": "authorized_user",
"universe_domain": "googleapis.com"
}
On a compute instance with an attached service account, IMDS can return a service-account OAuth2 token:
hacking3465@instance-20260509-053642:~$ curl -H "Metadata-Flavor: Google" \
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/660172346949-compute@developer.gserviceaccount.com/token
{"access_token":"ya29.c.c0AZ[REDACTED]","expires_in":3599,"token_type":"Bearer"}
Whichever route you followed plug the OAuth2 credential into GCPwn and set project the project after loading the token:
Input: oauth2 my_compute_oauth_token --token "ya29.c.c0AZ4bNpad[REDACTED]"
[*] Project ID of credentials is: Unknown
[*] Credentials successfully added
Loading in OAuth2 token. Note it might be expired based on how long its existed...
[*] Loaded credentials my_compute_oauth_token
(Unknown:my_compute_oauth_token)> modules run enum_cloudstorage
(Unknown:my_compute_oauth_token)> projects set <PROJECT_ID>
(<PROJECT_ID>:my_compute_oauth_token)> modules run enum_cloudstorage
[*] Target project 1/1: <PROJECT_ID>
[**] Reviewing test_[TRUNCATED]
[*] GCPwn found 1 Buckets in project <PROJECT_ID>
[*] TEXT OUTPUT (<PROJECT_ID>)
Resource Type: Buckets
Columns: name | location | blobs
Rows: showing 1 of 1
[TRUNCATED]
A standalone OAuth2 token cannot be refreshed unless you also have refresh material.
When a token expires, obtain a new token for the same principal and update the existing credential name:
creds update redteam-token --type oauth2 --token ya29.NEWTOKEN... --assumeService accounts are included in IAM bindings throughout GCP environments. Users can generate long-lasting static JSON API keys for service accounts which can then be used in various tools/SDKs to make API calls as the service account.
# Obtain a service account JSON key file
# (usually via IAM -> Service Accounts -> Keys)
# Load the key into GCPwn at startup
service-acc-key app-sa --service-file /tmp/app-sa.json| Field | Required | Source |
|---|---|---|
credential_name |
Yes | Operator-defined alias |
--service-file |
Yes | Service account JSON key file path |
Service account auth requires a JSON key file. Operators usually obtain this from IAM key-management workflows (or recover it from an accessible host/workspace path).
Typical file shape:
{
"type": "service_account",
"project_id": "example-project",
"private_key_id": "[REDACTED]",
"private_key": "-----BEGIN PRIVATE KEY-----\n[REDACTED]\n-----END PRIVATE KEY-----\n",
"client_email": "sa-name@example-project.iam.gserviceaccount.com",
"client_id": "[REDACTED]",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token"
}Treat this file like a password-equivalent secret.
chmod 600 /tmp/app-sa.jsonAt startup:
service-acc-key app-sa --service-file /tmp/app-sa.json
The tool should auto-detect the project based off the project_id field in the key. However, depending on the key/project context, explicitly setting the active project might be required:
(Unknown:app-sa)> projects set <PROJECT_ID>
(<PROJECT_ID>:app-sa)> modules run enum_cloudstorage
Service account keys don't auto-refresh like the ADC example. If you recover another keyf or the same principle you can update a credname with
creds update app-sa --type service --service-file /tmp/app-sa.json --assume-
creds infoprints current credential summary and discovered permission view. -
creds info --csvexports flattened permission rows for review/filtering. -
creds tokeninfoworks for OAuth-style creds and is metadata enrichment only. -
creds setupdates stored email/project metadata for a credential context.
| Error Pattern | Meaning | Remediation |
|---|---|---|
Must supply token via --token |
OAuth2 mode called without token | Re-run with --token <access_token>
|
File ... does not exist |
ADC/service file path invalid | Verify path and re-run |
ADC not setup |
No default ADC available | Run gcloud auth application-default login and gcloud config project set <PROJECT_ID> before starting gcpwn |
Can't perform tokeninfo operations with a service account token |
tokeninfo used with service-account creds |
Use tokeninfo for OAuth-style creds only |
| Credential refresh errors | Expired/invalid refresh state | Your crednetials/token are expired. Re-authenticate and run creds update if you have a new token to replace your current expired session with |
- Authentication Reference
- Workspace Instructions
- CLI Module Reference
- Downloads to Disk
- Data View/Export
- IAM Enumeration and Analysis Workflow
- Troubleshooting and FAQ