legido-ai/mcp-github-app-auth
If you are the rightful owner of mcp-github-app-auth and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
An MCP server that uses GitHub App authentication for GitHub operations.
MCP GitHub App Server
A lightweight MCP (Model Context Protocol) server that provides GitHub operations using GitHub App authentication instead of personal access tokens.
Table of Contents
- Prerequisites
- Installation
- Usage
- Integration with Claude Desktop
- Integration with Google Gemini CLI
- Testing
- Security Notes
Prerequisites
- A GitHub App installed with repository permissions for Contents (Read & write) and Pull requests (Read & write)
- Required environment variables:
GITHUB_APP_ID- Your GitHub App IDGITHUB_PRIVATE_KEY- Your GitHub App private key (PEM format)GITHUB_INSTALLATION_ID- Your GitHub App installation ID
Tools
The server implements the standard MCP protocol and provides one tool:
get_token: Obtain a temporary GitHub token for accessing private repositories using GitHub App authentication- Parameters:
owner(string, required): GitHub repository owner/organizationrepo(string, required): GitHub repository name
- Returns: A temporary GitHub token (valid for ~1 hour) that can be used with Git commands and GitHub REST API calls
- Parameters:
What is get_token?
The get_token tool generates a temporary GitHub authentication token that can be used for various Git operations AND GitHub API calls. This is NOT just for cloning - the token can be used for:
Git Operations:
- git clone: Clone private repositories
- git push: Push commits to remote repositories
- git pull: Pull updates from remote repositories
- git fetch: Fetch remote branches and tags
- Any other Git operation that requires authentication
GitHub REST API Operations:
- Create/manage issues: Create, update, comment on issues
- Pull requests: Create, review, merge pull requests
- Repository management: List contents, download files, get repository info
- Releases: Create and manage releases
- Any GitHub REST API endpoint: The token works with all authenticated API operations
Token Format:
For Git operations, use the token in URLs:
https://x-access-token:<GITHUB_TOKEN>@github.com/<ORGANIZATION>/<REPOSITORY>.git
For GitHub REST API operations, use the token in the Authorization header:
Authorization: Bearer <GITHUB_TOKEN>
Important Notes for Agents:
- The token is temporary and expires after approximately 1 hour
- The token can be used for ANY Git operation that requires authentication (clone, push, pull, fetch, etc.)
- The token can also be used for ANY GitHub REST API operation (create issues, PRs, manage repos, etc.)
- You do NOT need to call
get_tokenseparately for each operation - one token works for all Git and API operations - If an operation fails with authentication errors, the token may have expired - simply call
get_tokenagain to get a fresh token
This server does not perform Git operations itself, but provides temporary GitHub tokens for use with standard Git commands.
Installation
pip install .
Usage
Docker Usage
Pull the pre-built image from GitHub Container Registry:
docker pull ghcr.io/legido-ai/mcp-github-app-auth:latest
Or build locally from source:
docker build . -t mcp-github-app-auth
Testing the Server
This server implements the Model Context Protocol (MCP), which requires a proper initialization handshake before any operations can be performed. Direct JSON-RPC requests without initialization will be rejected.
Direct JSON-RPC Commands with Initialization
To test the server, you must send the full initialization sequence manually:
- Get the tools:
(
echo '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "manual-test", "version": "1.0"}}}'; \
echo '{"jsonrpc": "2.0", "method": "notifications/initialized"}'; \
echo '{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}'
) | docker run -i --rm \
-e GITHUB_APP_ID="$GITHUB_APP_ID" \
-e GITHUB_PRIVATE_KEY="$GITHUB_PRIVATE_KEY" \
-e GITHUB_INSTALLATION_ID="$GITHUB_INSTALLATION_ID" \
ghcr.io/legido-ai/mcp-github-app-auth
- Get a token. In this example we want to get a token for private Github repository https://github.com/my-org/my-private-repo:
(
echo '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "manual-test", "version": "1.0"}}}'; \
echo '{"jsonrpc": "2.0", "method": "notifications/initialized"}'; \
echo '{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "get_token", "arguments": {"owner": "my-org", "repo": "my-private-repo"}}}'
) | docker run -i --rm \
-e GITHUB_APP_ID="$GITHUB_APP_ID" \
-e GITHUB_PRIVATE_KEY="$GITHUB_PRIVATE_KEY" \
-e GITHUB_INSTALLATION_ID="$GITHUB_INSTALLATION_ID" \
ghcr.io/legido-ai/mcp-github-app-auth
Using with MCP Clients:
The server is designed to be used with MCP-compatible clients such as:
- Claude Desktop/Code
- Google Gemini CLI
- Other MCP-compatible AI assistants
See the integration sections below for setup instructions.
Note on Direct JSON-RPC Testing:
MCP requires a three-step initialization sequence before accepting requests:
- Client sends
initializerequest with protocol version and capabilities - Server responds with its capabilities
- Client sends
initializednotification - Only then can the client send requests like
tools/listortools/call
Why direct commands without initialization don't work:
Simple echo commands bypass the initialization sequence and will fail with:
WARNING:root:Failed to validate request: Received request before initialization was complete
This is correct MCP protocol behavior. The commands above include the full initialization sequence required by the protocol.
Using the Token for Git Operations
Once you have the token, you can use it for various Git operations:
Clone a repository:
git clone https://x-access-token:ghs_tokenhere@github.com/fictional-org/private-repo.git
Clone a specific branch:
git clone -b feature-branch https://x-access-token:ghs_tokenhere@github.com/fictional-org/private-repo.git
Push to a repository:
cd private-repo
# Make some changes
git add .
git commit -m "Update files"
git push https://x-access-token:ghs_tokenhere@github.com/fictional-org/private-repo.git main
Pull updates:
git pull https://x-access-token:ghs_tokenhere@github.com/fictional-org/private-repo.git main
Fetch remote branches:
git fetch https://x-access-token:ghs_tokenhere@github.com/fictional-org/private-repo.git
Set as remote URL:
git remote set-url origin https://x-access-token:ghs_tokenhere@github.com/fictional-org/private-repo.git
# Now you can use regular git push/pull commands
git push origin main
Using the Token for GitHub API Operations
The token can also be used with GitHub's REST API for various operations beyond Git commands:
Create an Issue:
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ghs_tokenhere" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/fictional-org/private-repo/issues \
-d '{"title":"Found a bug","body":"Description of the issue","labels":["bug"]}'
Create a Pull Request:
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ghs_tokenhere" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/fictional-org/private-repo/pulls \
-d '{"title":"Amazing new feature","body":"Please pull these changes","head":"feature-branch","base":"main"}'
Add a Comment to an Issue:
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ghs_tokenhere" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/fictional-org/private-repo/issues/1/comments \
-d '{"body":"This is a comment on the issue"}'
List Repository Contents:
curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ghs_tokenhere" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/fictional-org/private-repo/contents/path/to/directory
Download a File from Private Repository:
curl -H "Authorization: Bearer ghs_tokenhere" \
-H "Accept: application/vnd.github.v3.raw" \
-o downloaded-file.txt \
-L https://api.github.com/repos/fictional-org/private-repo/contents/path/to/file.txt
Get Repository Information:
curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ghs_tokenhere" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/fictional-org/private-repo
List Pull Requests:
curl -L \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ghs_tokenhere" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/fictional-org/private-repo/pulls
Create a Release:
curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ghs_tokenhere" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/fictional-org/private-repo/releases \
-d '{"tag_name":"v1.0.0","name":"Release v1.0.0","body":"Description of the release"}'
End-to-End Example
Example 1: Clone a Repository
- Pull the pre-built image:
docker pull ghcr.io/legido-ai/mcp-github-app-auth:latest
- Get a GitHub token:
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "get_token", "arguments": {"owner": "fictional-org", "repo": "private-repo"}}}' | \
docker run -i --rm \
-e GITHUB_APP_ID="$GITHUB_APP_ID" \
-e GITHUB_PRIVATE_KEY="$GITHUB_PRIVATE_KEY" \
-e GITHUB_INSTALLATION_ID="$GITHUB_INSTALLATION_ID" \
ghcr.io/legido-ai/mcp-github-app-auth:latest
- Use the returned token to clone the repository:
# Extract the token from the response (example shows ghs_tokenhere)
git clone https://x-access-token:ghs_tokenhere@github.com/fictional-org/private-repo.git
Example 2: Clone, Modify, and Push
- Get a GitHub token:
TOKEN=$(echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "get_token", "arguments": {"owner": "fictional-org", "repo": "private-repo"}}}' | \
docker run -i --rm \
-e GITHUB_APP_ID="$GITHUB_APP_ID" \
-e GITHUB_PRIVATE_KEY="$GITHUB_PRIVATE_KEY" \
-e GITHUB_INSTALLATION_ID="$GITHUB_INSTALLATION_ID" \
ghcr.io/legido-ai/mcp-github-app-auth:latest | \
jq -r '.result.content[0].text' | grep -oP 'ghs_\w+')
- Clone the repository:
git clone https://x-access-token:$TOKEN@github.com/fictional-org/private-repo.git
cd private-repo
- Make changes and push:
echo "# New content" >> README.md
git add README.md
git commit -m "Update README"
git push https://x-access-token:$TOKEN@github.com/fictional-org/private-repo.git main
Example 3: Using Token with Multiple Operations
# Get token
TOKEN=$(echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "get_token", "arguments": {"owner": "fictional-org", "repo": "private-repo"}}}' | \
docker run -i --rm \
-e GITHUB_APP_ID="$GITHUB_APP_ID" \
-e GITHUB_PRIVATE_KEY="$GITHUB_PRIVATE_KEY" \
-e GITHUB_INSTALLATION_ID="$GITHUB_INSTALLATION_ID" \
ghcr.io/legido-ai/mcp-github-app-auth:latest | \
jq -r '.result.content[0].text' | grep -oP 'ghs_\w+')
# Clone repository
git clone https://x-access-token:$TOKEN@github.com/fictional-org/private-repo.git
cd private-repo
# Set remote URL with token for subsequent operations
git remote set-url origin https://x-access-token:$TOKEN@github.com/fictional-org/private-repo.git
# Now you can use regular git commands
git pull origin main
git push origin main
git fetch --all
Integration with Claude Desktop
⚠️ CRITICAL: Variable Expansion Does Not Work
Claude Desktop/Code does NOT support environment variable expansion in configuration files.
This is a fundamental limitation of Claude's configuration system. If you try to use variables like $GITHUB_APP_ID, Claude will treat them as literal strings, not as references to environment variables.
What This Means:
- ❌
GITHUB_APP_ID=$GITHUB_APP_ID→ Claude passes the literal string"$GITHUB_APP_ID"to Docker - ❌ This causes authentication to fail with errors like "Could not parse the provided public key"
- ❌ The MCP server receives invalid credentials and cannot authenticate with GitHub
Why This Happens:
Claude's JSON configuration parser does not perform shell-style variable substitution. The $VARIABLE syntax is passed unchanged to the underlying command, causing the Docker container to receive the literal string instead of the actual credential values.
❌ This Configuration WILL NOT WORK:
{
"projects": {
"/path/to/your/project": {
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_APP_ID=$GITHUB_APP_ID", ← Passed as literal "$GITHUB_APP_ID"
"-e",
"GITHUB_PRIVATE_KEY=$GITHUB_PRIVATE_KEY", ← Passed as literal string
"-e",
"GITHUB_INSTALLATION_ID=$GITHUB_INSTALLATION_ID", ← Not expanded
"ghcr.io/legido-ai/mcp-github-app-auth:latest"
]
}
}
}
}
}
Result: Authentication fails because the MCP receives literal strings instead of your actual credentials.
Option 1: Manual Configuration (Not Recommended)
You can manually edit ~/.claude.json with hardcoded values, but this is not recommended for security reasons:
{
"projects": {
"/path/to/your/project": {
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_APP_ID=123456",
"-e",
"GITHUB_PRIVATE_KEY=-----BEGIN RSA PRIVATE KEY-----\n...",
"-e",
"GITHUB_INSTALLATION_ID=78910",
"ghcr.io/legido-ai/mcp-github-app-auth:latest"
]
}
}
}
}
}
✅ Option 2: Automated Setup Script (Recommended)
Why You Need This Script:
Since Claude cannot expand variables, you need an external script to:
- Read your environment variables (
$GITHUB_APP_ID, etc.) - Extract their actual values
- Write those literal values into Claude's
~/.claude.jsonconfiguration file
This script automates the process and is the recommended solution for setting up the MCP server with Claude.
The Script:
This script is available in the docker-claude-code repository or can be copied from below:
#!/bin/bash
#
# Setup script for configuring GitHub MCP server in Claude Code
# This script properly expands environment variables when adding the MCP server configuration
#
set -e
echo "Configuring GitHub MCP server for Claude Code..."
# Check if required environment variables are set
if [ -z "$GITHUB_APP_ID" ] || [ -z "$GITHUB_INSTALLATION_ID" ] || [ -z "$GITHUB_PRIVATE_KEY" ]; then
echo "ERROR: Missing required environment variables!"
echo "Please ensure the following environment variables are set:"
echo " - GITHUB_APP_ID"
echo " - GITHUB_INSTALLATION_ID"
echo " - GITHUB_PRIVATE_KEY"
exit 1
fi
# Check if Python is available
if ! command -v python3 &> /dev/null; then
echo "ERROR: python3 is required but not found in PATH"
exit 1
fi
# Ensure .claude.json exists
if [ ! -f "$HOME/.claude.json" ]; then
echo "Creating $HOME/.claude.json..."
echo '{}' > "$HOME/.claude.json"
fi
# Use Python to safely update the JSON configuration with expanded environment variables
python3 << 'EOFPYTHON'
import json
import os
import sys
config_path = os.path.expanduser("~/.claude.json")
# Read the current config
try:
with open(config_path, "r") as f:
config = json.load(f)
except Exception as e:
print(f"ERROR: Failed to read {config_path}: {e}", file=sys.stderr)
sys.exit(1)
# Get environment variables with actual values
github_app_id = os.environ.get("GITHUB_APP_ID")
github_installation_id = os.environ.get("GITHUB_INSTALLATION_ID")
github_private_key = os.environ.get("GITHUB_PRIVATE_KEY")
if not all([github_app_id, github_installation_id, github_private_key]):
print("ERROR: Missing required environment variables", file=sys.stderr)
sys.exit(1)
# Create MCP server configuration with expanded values
mcp_config = {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
f"GITHUB_APP_ID={github_app_id}",
"-e",
f"GITHUB_PRIVATE_KEY={github_private_key}",
"-e",
f"GITHUB_INSTALLATION_ID={github_installation_id}",
"ghcr.io/legido-ai/mcp-github-app-auth:latest"
]
}
# Get current working directory
cwd = os.getcwd()
# Initialize nested structure if needed
if "projects" not in config:
config["projects"] = {}
if cwd not in config["projects"]:
config["projects"][cwd] = {}
if "mcpServers" not in config["projects"][cwd]:
config["projects"][cwd]["mcpServers"] = {}
# Add/update the github MCP server
config["projects"][cwd]["mcpServers"]["github"] = mcp_config
# Create backup
backup_path = f"{config_path}.backup"
try:
with open(config_path, "r") as f:
with open(backup_path, "w") as b:
b.write(f.read())
except Exception:
pass # Ignore backup errors
# Write back the updated config
try:
with open(config_path, "w") as f:
json.dump(config, f, indent=2)
print(f"✓ MCP configuration updated successfully for project: {cwd}")
print(f"✓ Backup saved to: {backup_path}")
except Exception as e:
print(f"ERROR: Failed to write {config_path}: {e}", file=sys.stderr)
sys.exit(1)
EOFPYTHON
echo ""
echo "GitHub MCP server configured successfully!"
echo ""
echo "To verify the configuration, run:"
echo " claude mcp list"
echo ""
echo "NOTE: This configuration uses expanded environment variable values."
echo "If you change your GitHub App credentials, you must run this script again."
Step-by-Step Setup Instructions:
-
Save the script as
setup-mcp-github.sh -
Make it executable:
chmod +x setup-mcp-github.sh -
Set your environment variables with your actual GitHub App credentials:
export GITHUB_APP_ID="123456" export GITHUB_INSTALLATION_ID="78910" export GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA... -----END RSA PRIVATE KEY-----" -
Run the setup script:
./setup-mcp-github.shThe script will:
- ✓ Validate that all required environment variables are set
- ✓ Read the actual values from your environment
- ✓ Create/update
~/.claude.jsonwith the literal values (not variable references) - ✓ Create a backup of your existing configuration
-
Verify the configuration:
claude mcp listYou should see:
✓ github: docker run -i --rm ... ghcr.io/legido-ai/mcp-github-app-auth:latest - Connected
Important Notes:
- The script writes the actual credential values (not
$VARIABLEreferences) into~/.claude.json - If you change your GitHub App credentials, you must run this script again to update the configuration
- The script creates a backup at
~/.claude.json.backupbefore making changes
Integration with Google Gemini CLI
IMPORTANT: Google Gemini CLI also does not support environment variable expansion in configuration files. Variables like $GITHUB_APP_ID will be passed as literal strings, not their values.
You must manually edit your Gemini CLI settings.json (located at ~/.gemini/settings.json) with the actual expanded values:
{
"mcpServers": {
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_APP_ID=123456",
"-e",
"GITHUB_PRIVATE_KEY=-----BEGIN RSA PRIVATE KEY-----\n...",
"-e",
"GITHUB_INSTALLATION_ID=78910",
"ghcr.io/legido-ai/mcp-github-app-auth:latest"
],
"trust": true,
"timeout": 30000
}
}
}
Verify the connection:
gemini mcp list
You should see:
✓ github: docker run -i --rm ... ghcr.io/legido-ai/mcp-github-app-auth:latest (stdio) - Connected
Troubleshooting
Common Authentication Errors
Error: "Could not parse the provided public key"
Symptom:
ERROR: Could not parse the provided public key
Failed to get installation token: 401 ...
Cause:
This error occurs when Claude passes literal variable names (like "$GITHUB_PRIVATE_KEY") to the MCP server instead of the actual private key value.
Solution:
- ✅ Use the automated setup script to configure Claude
- ❌ Do NOT use
$VARIABLEsyntax in~/.claude.json - ✅ Ensure your
~/.claude.jsoncontains the actual credential values, not variable references
How to Verify:
# Check what's actually in your configuration
cat ~/.claude.json | grep -A 5 "GITHUB_PRIVATE_KEY"
If you see "$GITHUB_PRIVATE_KEY" or "GITHUB_PRIVATE_KEY=$GITHUB_PRIVATE_KEY", the variable was not expanded. Re-run the setup script.
Error: "Missing required environment variables"
Symptom:
ERROR: Missing GITHUB_APP_ID / GITHUB_INSTALLATION_ID / GITHUB_PRIVATE_KEY
Cause: The MCP server is not receiving the required environment variables.
Solution:
- Verify environment variables are set before running the setup script:
echo $GITHUB_APP_ID echo $GITHUB_INSTALLATION_ID echo $GITHUB_PRIVATE_KEY | head -1 - If any are empty, set them and re-run the setup script
- Ensure you're setting variables in the same shell session where you run the setup script
Error: MCP Server Shows as "Disconnected"
Symptom:
✗ github: docker run -i --rm ... ghcr.io/legido-ai/mcp-github-app-auth:latest - Disconnected
Possible Causes and Solutions:
-
Docker is not running:
docker ps # Should not error -
Docker image is not available:
docker pull ghcr.io/legido-ai/mcp-github-app-auth:latest -
Invalid credentials in configuration:
- Re-run the setup script with correct credentials
- Verify credentials work by testing manually:
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "get_token", "arguments": {"owner": "your-org", "repo": "your-repo"}}}' | \ docker run -i --rm \ -e GITHUB_APP_ID="$GITHUB_APP_ID" \ -e GITHUB_PRIVATE_KEY="$GITHUB_PRIVATE_KEY" \ -e GITHUB_INSTALLATION_ID="$GITHUB_INSTALLATION_ID" \ ghcr.io/legido-ai/mcp-github-app-auth:latest
Error: "401 Unauthorized" from GitHub API
Symptom:
Failed to get installation token: 401 {"message":"Bad credentials",...}
Possible Causes:
-
Incorrect GitHub App ID:
- Verify at:
https://github.com/settings/apps/your-app - The App ID is shown at the top of the settings page
- Verify at:
-
Wrong Private Key:
- Regenerate if needed at:
https://github.com/settings/apps/your-app - Scroll to "Private keys" section
- Ensure you're using the complete key including headers:
-----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY-----
- Regenerate if needed at:
-
Incorrect Installation ID:
- Find it in the installation URL:
https://github.com/settings/installations/INSTALLATION_ID - Or via API:
curl -H "Authorization: Bearer <jwt_token>" https://api.github.com/app/installations
- Find it in the installation URL:
How to Test Configuration Manually
To verify your setup works before configuring Claude:
# 1. Set environment variables
export GITHUB_APP_ID="your-app-id"
export GITHUB_INSTALLATION_ID="your-installation-id"
export GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----"
# 2. Test the MCP server directly
echo '{"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "get_token", "arguments": {"owner": "legido-ai", "repo": "tasks"}}}' | \
docker run -i --rm \
-e GITHUB_APP_ID="$GITHUB_APP_ID" \
-e GITHUB_PRIVATE_KEY="$GITHUB_PRIVATE_KEY" \
-e GITHUB_INSTALLATION_ID="$GITHUB_INSTALLATION_ID" \
ghcr.io/legido-ai/mcp-github-app-auth:latest
# 3. You should get a response with a token like:
# {"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"GitHub token for legido-ai/tasks: ghs_..."}]}}
If this works, your credentials are correct and you can proceed with Claude configuration.
Testing
Run tests with:
python3 -m pytest tests/ -v
Security Notes
- Installation tokens expire after approximately 1 hour
- The server caches and refreshes tokens automatically