.claude/skills/oauth-login/SKILL.md
Complete OAuth login flow and store tokens for verification. Use when browser verification requires authenticated sessions.
npx skillsauth add benjaminshoemaker/ai_coding_project_base oauth-loginInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Complete an OAuth login flow for browser verification. Opens a browser to the OAuth
consent page, waits for callback, and stores tokens in the project's .env file.
| Provider | OAuth 2.0 Endpoint | Scopes | |----------|-------------------|--------| | google | accounts.google.com | openid, email, profile | | github | github.com/login/oauth | read:user, user:email |
/oauth-login google
/oauth-login github
OAuth App Credentials Required
Before running this command, the user must have created an OAuth application with the provider and have the client ID and secret ready.
Google:
http://localhost:3847/oauth/callbackGitHub:
http://localhost:3847/oauth/callbackBrowser MCP Available
Playwright MCP or similar browser tool must be available for automated flow.
Copy this checklist and track progress:
OAuth Login Progress:
- [ ] Step 1: Check provider argument
- [ ] Step 2: Check for existing credentials
- [ ] Step 3: Collect OAuth app credentials
- [ ] Step 4: Generate state parameter
- [ ] Step 5: Build authorization URL
- [ ] Step 6: Start callback server
- [ ] Step 7: Open browser to auth URL
- [ ] Step 8: Wait for callback
- [ ] Step 9: Exchange code for tokens
- [ ] Step 10: Store tokens in .env
- [ ] Step 11: Verify token validity
- [ ] Step 12: Report success
If $1 is not provided or not recognized:
OAUTH LOGIN
===========
Usage: /oauth-login <provider>
Supported providers:
google - Google OAuth 2.0
github - GitHub OAuth
Example: /oauth-login google
Read .env file and check for existing OAuth tokens:
grep -E "^OAUTH_(GOOGLE|GITHUB)_" .env 2>/dev/null || true
If tokens exist for this provider, ask:
Question: "OAuth tokens for {provider} already exist. What would you like to do?"
Header: "Existing tokens"
Options:
- Label: "Refresh tokens"
Description: "Re-authenticate and get new tokens"
- Label: "Keep existing"
Description: "Exit without changes"
Use AskUserQuestion to collect OAuth app credentials:
Question: "Enter your {Provider} OAuth Client ID:"
Header: "Client ID"
Then:
Question: "Enter your {Provider} OAuth Client Secret:"
Header: "Client Secret"
Add to .env:
OAUTH_{PROVIDER}_CLIENT_ID=<client_id>
OAUTH_{PROVIDER}_CLIENT_SECRET=<client_secret>
After writing to .env, read back the file to confirm the credentials were stored correctly. If the .env file does not exist yet, create it first.
Create a temporary callback server to receive the OAuth code.
Write the contents of callback-server.js to a temp file, then execute it:
# Copy callback server script to temp location
cp "$(dirname "$0")/callback-server.js" /tmp/oauth-callback-server.js 2>/dev/null || \
cp .claude/skills/oauth-login/callback-server.js /tmp/oauth-callback-server.js
# Start callback server as BACKGROUND PROCESS
node /tmp/oauth-callback-server.js &
CALLBACK_PID=$!
echo "Callback server started (PID: $CALLBACK_PID, background process)"
# Verify the server started successfully
sleep 1
curl -sf http://localhost:3847/ -o /dev/null 2>&1 || echo "WARNING: Callback server may not have started"
Verify server is listening before proceeding by running curl -sf http://localhost:3847/ -o /dev/null and checking the exit code. If the server failed to start (port in use, Node.js error), check the error output and try an alternate port (3848, 3849) before continuing.
Google:
https://accounts.google.com/o/oauth2/v2/auth?
client_id={CLIENT_ID}&
redirect_uri=http://localhost:3847/oauth/callback&
response_type=code&
scope=openid%20email%20profile&
access_type=offline&
prompt=consent
GitHub:
https://github.com/login/oauth/authorize?
client_id={CLIENT_ID}&
redirect_uri=http://localhost:3847/oauth/callback&
scope=read:user%20user:email
Use Playwright MCP to open the authorization URL:
mcp__playwright__browser_navigate with url={auth_url}
Display to user:
OAUTH AUTHORIZATION
===================
Opening browser for {Provider} authorization...
Please complete the login in the browser window.
This command will wait for you to complete authorization.
If the browser doesn't open, visit this URL:
{auth_url}
Poll for the callback result:
# Wait up to 120 seconds for callback
for i in $(seq 1 120); do
if [ -f /tmp/oauth-code.txt ]; then
CODE=$(cat /tmp/oauth-code.txt)
rm /tmp/oauth-code.txt
break
fi
if [ -f /tmp/oauth-error.txt ]; then
ERROR=$(cat /tmp/oauth-error.txt)
rm /tmp/oauth-error.txt
echo "OAuth error: $ERROR"
exit 1
fi
sleep 1
done
Google token exchange:
curl -s -X POST https://oauth2.googleapis.com/token \
-d "code=$CODE" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "redirect_uri=http://localhost:3847/oauth/callback" \
-d "grant_type=authorization_code"
GitHub token exchange:
curl -s -X POST https://github.com/login/oauth/access_token \
-H "Accept: application/json" \
-d "code=$CODE" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET"
Check the HTTP response status code from the token exchange before parsing. If the response contains an error field or is not valid JSON, report the error and do not proceed to token storage.
Parse response for:
access_tokenrefresh_token (Google only)expires_inAfter obtaining the token, verify it is valid by making a lightweight test API call (e.g., fetch the user profile endpoint). If the test call fails, report the token as invalid and retry the OAuth flow.
Google verification:
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" https://www.googleapis.com/oauth2/v2/userinfo
GitHub verification:
curl -s -H "Authorization: Bearer $ACCESS_TOKEN" https://api.github.com/user
If the response indicates an error (HTTP 401 or invalid token), report: "Token verification failed — token appears invalid" and restart the OAuth flow from Step 5.
Calculate expiry timestamp and store in .env:
EXPIRY=$(date -v+${EXPIRES_IN}S +%s 2>/dev/null || date -d "+${EXPIRES_IN} seconds" +%s)
Add/update in .env:
OAUTH_{PROVIDER}_ACCESS_TOKEN={access_token}
OAUTH_{PROVIDER}_REFRESH_TOKEN={refresh_token}
OAUTH_{PROVIDER}_TOKEN_EXPIRY={expiry_timestamp}
After writing tokens to .env, read back the file to verify the token variables are present and non-empty. Do not proceed to the next step if tokens are missing.
Update .claude/verification-config.json to use OAuth:
{
"auth": {
"strategy": "oauth",
"provider": "{provider}",
"tokenVar": "OAUTH_{PROVIDER}_ACCESS_TOKEN",
"refreshTokenVar": "OAUTH_{PROVIDER}_REFRESH_TOKEN",
"expiryVar": "OAUTH_{PROVIDER}_TOKEN_EXPIRY"
}
}
After updating verification-config.json, read the file back to confirm the auth section was written correctly and the JSON is valid.
# Kill callback server if still running
kill $CALLBACK_PID 2>/dev/null || true
rm -f /tmp/oauth-callback-server.js /tmp/oauth-code.txt /tmp/oauth-error.txt
OAUTH LOGIN COMPLETE
====================
Provider: {Provider}
Access Token: Stored in .env as OAUTH_{PROVIDER}_ACCESS_TOKEN
Refresh Token: {Stored | Not provided (GitHub)}
Token Expiry: {date/time}
verification-config.json updated with OAuth settings.
The access token will be automatically refreshed before verification runs
if it's within 5 minutes of expiry.
This command also handles token refresh when called with --refresh:
/oauth-login google --refresh
Refresh flow:
OAUTH_{PROVIDER}_REFRESH_TOKEN from .envGoogle refresh:
curl -s -X POST https://oauth2.googleapis.com/token \
-d "refresh_token=$REFRESH_TOKEN" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET" \
-d "grant_type=refresh_token"
OAUTH_{PROVIDER}_ACCESS_TOKEN and OAUTH_{PROVIDER}_TOKEN_EXPIRY in .envNote: GitHub tokens don't expire unless revoked, so no refresh needed.
| Error | Action | |-------|--------| | Callback server port in use | Try port 3848, 3849, etc. | | User cancels consent | Show error, suggest retry | | Token exchange fails | Show API error, suggest checking credentials | | Browser MCP unavailable | Provide manual URL, ask user to paste code |
If user is still in browser after 120s timeout:
If browser MCP is completely unavailable:
If OAuth app credentials are invalid:
If callback server cannot start on any port:
.env which should be in .gitignoretesting
Audit project alignment with VISION.md, identify SDLC gaps, and generate feature proposals. Use when reviewing strategic direction or planning new features.
development
Run code-verification on a specific task. Use to verify a single task's acceptance criteria after implementation.
testing
Resolve Vercel preview deployment URL for the current git branch. Invoked by browser-verification when deployment.enabled is true, or directly to check deployment status. Use to check deployment status or when browser verification needs a URL.
tools
Discover and sync all toolkit-using projects with the latest skills. Use when skills are modified, after the post-commit hook reminds you, or to batch-sync multiple projects.