This guide explains how to set up OAuth credentials and obtain access tokens for running integration tests.
The integration tests (tests/test_oauth_integration.py) verify that the OAuth implementation works with real GitHub and Google APIs. To run these tests, you need:
- OAuth App Credentials - Client ID and Secret from GitHub/Google
- Access Tokens - Pre-obtained tokens for testing authenticated endpoints
- Environment Variables - Configuration for the tests
# 1. Get OAuth credentials (see detailed instructions below)
# 2. Use the helper script to obtain tokens
python examples/auth/oauth_token_helper.py
# 3. Set environment variables
export GITHUB_CLIENT_ID="your_client_id"
export GITHUB_CLIENT_SECRET="your_client_secret"
export GITHUB_ACCESS_TOKEN="gho_..."
export GOOGLE_CLIENT_ID="your_client_id.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="your_client_secret"
export GOOGLE_ACCESS_TOKEN="ya29..."
export GOOGLE_REFRESH_TOKEN="1//..."
# 4. Run integration tests
pytest tests/test_oauth_integration.py -v -m integration-
Go to GitHub Settings → Developer settings → OAuth Apps
- Direct link: https://github.com/settings/developers
-
Click "New OAuth App"
-
Fill in the application details:
Application name: NextMCP OAuth Testing Homepage URL: http://localhost:8080 Authorization callback URL: http://localhost:8080/oauth/callback -
Click "Register application"
-
You'll see your Client ID - copy this
-
Click "Generate a new client secret" and copy the secret
⚠️ Save this immediately - you won't be able to see it again!
You have two options:
python examples/auth/oauth_token_helper.py --provider githubThe script will:
- Generate an authorization URL
- Open your browser to authorize
- Start a local callback server
- Automatically extract the access token
- Show you the environment variables to set
-
Generate Authorization URL:
python -c " from nextmcp.auth import GitHubOAuthProvider provider = GitHubOAuthProvider( client_id='YOUR_CLIENT_ID', client_secret='YOUR_CLIENT_SECRET', scope=['read:user', 'repo'] ) auth_data = provider.generate_authorization_url() print(f'Visit: {auth_data[\"url\"]}') print(f'Verifier: {auth_data[\"verifier\"]}') "
-
Visit the URL in your browser and click "Authorize"
-
Copy the code from the callback URL:
http://localhost:8080/oauth/callback?code=AUTHORIZATION_CODE&state=... -
Exchange code for token:
python -c " import asyncio from nextmcp.auth import GitHubOAuthProvider async def get_token(): provider = GitHubOAuthProvider( client_id='YOUR_CLIENT_ID', client_secret='YOUR_CLIENT_SECRET' ) token_data = await provider.exchange_code_for_token( code='AUTHORIZATION_CODE', state='STATE_FROM_URL', verifier='VERIFIER_FROM_STEP_1' ) print(f'Access Token: {token_data[\"access_token\"]}') asyncio.run(get_token()) "
-
Set environment variable:
export GITHUB_ACCESS_TOKEN="gho_xxxxxxxxxxxxxxxxxxxxx"
# Add to your ~/.bashrc or ~/.zshrc
export GITHUB_CLIENT_ID="your_client_id_here"
export GITHUB_CLIENT_SECRET="your_client_secret_here"
export GITHUB_ACCESS_TOKEN="gho_your_access_token_here"Or create a .env file:
# .env
GITHUB_CLIENT_ID=your_client_id_here
GITHUB_CLIENT_SECRET=your_client_secret_here
GITHUB_ACCESS_TOKEN=gho_your_access_token_hereThen load it:
export $(cat .env | xargs)-
Go to Google Cloud Console: https://console.cloud.google.com
-
Create a new project:
- Click the project dropdown at the top
- Click "New Project"
- Name: "NextMCP OAuth Testing"
- Click "Create"
-
Enable APIs:
- Go to "APIs & Services" → "Library"
- Search for and enable:
- Google Drive API
- Gmail API
- Google+ API (for userinfo)
-
Go to "APIs & Services" → "Credentials"
-
Click "Create Credentials" → "OAuth client ID"
-
If prompted, configure the OAuth consent screen:
- User Type: External
- App name: NextMCP OAuth Testing
- User support email: Your email
- Developer contact: Your email
- Scopes: Add these scopes:
.../auth/userinfo.email.../auth/userinfo.profile.../auth/drive.readonly.../auth/gmail.readonly
- Test users: Add your email address
-
Create OAuth Client ID:
- Application type: Web application
- Name: NextMCP OAuth Testing
- Authorized redirect URIs:
http://localhost:8080/oauth/callback
- Click "Create"
-
Download credentials or copy:
- Client ID (ends in
.apps.googleusercontent.com) - Client Secret
- Client ID (ends in
python examples/auth/oauth_token_helper.py --provider googleThe script will:
- Generate an authorization URL with offline access
- Open your browser to authorize
- Start a local callback server
- Extract access token AND refresh token
- Show you the environment variables to set
-
Generate Authorization URL:
python -c " from nextmcp.auth import GoogleOAuthProvider provider = GoogleOAuthProvider( client_id='YOUR_CLIENT_ID.apps.googleusercontent.com', client_secret='YOUR_CLIENT_SECRET', scope=[ 'https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/drive.readonly' ] ) auth_data = provider.generate_authorization_url() print(f'Visit: {auth_data[\"url\"]}') print(f'Verifier: {auth_data[\"verifier\"]}') "
-
Visit the URL, sign in, and authorize the app
-
Copy the code from the callback URL
-
Exchange code for tokens:
python -c " import asyncio from nextmcp.auth import GoogleOAuthProvider async def get_token(): provider = GoogleOAuthProvider( client_id='YOUR_CLIENT_ID', client_secret='YOUR_CLIENT_SECRET' ) token_data = await provider.exchange_code_for_token( code='AUTHORIZATION_CODE', state='STATE_FROM_URL', verifier='VERIFIER_FROM_STEP_1' ) print(f'Access Token: {token_data[\"access_token\"]}') print(f'Refresh Token: {token_data.get(\"refresh_token\", \"N/A\")}') asyncio.run(get_token()) "
-
Set environment variables:
export GOOGLE_ACCESS_TOKEN="ya29.xxxxxxxxxxxxx" export GOOGLE_REFRESH_TOKEN="1//xxxxxxxxxxxxx" # If provided
# Add to your ~/.bashrc or ~/.zshrc
export GOOGLE_CLIENT_ID="your_client_id.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="your_client_secret"
export GOOGLE_ACCESS_TOKEN="ya29.your_access_token"
export GOOGLE_REFRESH_TOKEN="1//your_refresh_token"Or create a .env file:
# .env
GOOGLE_CLIENT_ID=your_client_id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your_client_secret
GOOGLE_ACCESS_TOKEN=ya29.your_access_token
GOOGLE_REFRESH_TOKEN=1//your_refresh_token# Activate virtual environment
source .venv/bin/activate
# Run integration tests with verbose output
pytest tests/test_oauth_integration.py -v -m integration# GitHub only
pytest tests/test_oauth_integration.py::TestGitHubOAuthIntegration -v
# Google only
pytest tests/test_oauth_integration.py::TestGoogleOAuthIntegration -v# Test GitHub user info retrieval
pytest tests/test_oauth_integration.py::TestGitHubOAuthIntegration::test_github_get_user_info -v
# Test Google token refresh
pytest tests/test_oauth_integration.py::TestGoogleOAuthIntegration::test_google_token_refresh -v# Regular test run automatically skips integration tests
pytest
# Or explicitly skip them
pytest -m "not integration"This means the required environment variables are not set. Check:
# Verify environment variables are set
echo $GITHUB_CLIENT_ID
echo $GITHUB_ACCESS_TOKEN
echo $GOOGLE_CLIENT_ID
echo $GOOGLE_ACCESS_TOKEN
# If empty, source your environment file
source ~/.bashrc # or ~/.zshrc
# or
export $(cat .env | xargs)Access tokens expire! GitHub tokens last indefinitely (until revoked), but Google access tokens expire after 1 hour.
Solution: Re-run the helper script to get a fresh token:
python examples/auth/oauth_token_helper.py --provider googleFor Google, use the refresh token to get a new access token:
pytest tests/test_oauth_integration.py::TestGoogleOAuthIntegration::test_google_token_refresh -v -s
# Copy the new access token from the outputMake sure your OAuth app has http://localhost:8080/oauth/callback as an authorized redirect URI.
Your app is in testing mode. Add your Google account as a test user:
- Go to Google Cloud Console
- APIs & Services → OAuth consent screen
- Scroll to "Test users"
- Click "Add Users"
- Add your email address
OAuth APIs have rate limits. If you hit them:
- GitHub: Wait a bit or use a different account
- Google: Wait for the quota to reset (usually hourly)
Add to .gitignore:
.env
.env.*
*_credentials.json
*_token.json
Use environment variables or a secure secrets manager in production.
For testing, tokens with minimal scopes are recommended:
- GitHub:
read:useris sufficient for basic tests - Google: Use
userinfo.profileanduserinfo.emailonly
- Authorization URL Generation - Verifies PKCE challenge and URL formatting
- User Info Retrieval - Tests GitHub API
/userendpoint - Authentication Flow - Tests complete auth with access token
- Error Handling - Verifies invalid tokens are rejected
- Authorization URL Generation - Verifies offline access parameters
- User Info Retrieval - Tests Google userinfo API
- Authentication Flow - Tests complete auth with access token
- Token Refresh - Tests refresh token flow (unique to Google)
- Error Handling - Verifies invalid tokens/refresh tokens are rejected
Once you have integration tests passing, you can:
- Build OAuth-protected tools using the examples in
examples/auth/ - Implement OAuth callback servers for production use
- Add custom OAuth providers by extending
OAuthProvider - Test with your own APIs using the authenticated tokens
For production deployments, see the examples in examples/auth/ for complete OAuth flow implementations.