
Authentication Patterns
- 93 installs
- 325 repo stars
- Updated August 2, 2026
- athola/claude-night-market
Authentication-patterns is an agent skill that standardizes interactive CLI authentication with caching before workflow commands run.
About
Authentication-patterns is an agent skill from the Claude Night Market / Leyline line that shows how to integrate interactive authentication into existing bash workflows. Solo builders hitting GitHub, or similar services, from custom commands often copy-paste auth checks that exit with opaque errors; this skill replaces that with sourced interactive_auth modules and ensure_auth gates. Examples contrast the old manual gh auth status pattern with cached interactive auth, then apply it to PR review and issue creation flows that call gh and the GitHub API. Benefits called out include user prompts when credentials are missing, short-lived status caching to avoid repeated checks, day-long session persistence for local dev, and CI compatibility when tokens are injected. The pattern is meant to be copied at the top of any workflow that needs network-backed CLIs so agents consistently authenticate before fetching PRs, comments, or creating issues.
- ensure_auth pattern replaces brittle manual gh auth status checks
- Auth status cached for 5 minutes with session persistence up to 24 hours
- Works in CI/CD when GITHUB_TOKEN is provided alongside interactive login flows
- Documented wiring for PR review and create-issue style slash commands
- Pre-flight check at workflow start for any external service access
Authentication Patterns by the numbers
- 93 all-time installs (skills.sh)
- Ranked #836 of 2,715 Automation & Workflows skills by installs in the Skillselion catalog
- Security screen: HIGH risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/athola/claude-night-market --skill authentication-patternsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 93 |
|---|---|
| repo stars | ★ 325 |
| Security audit | 2 / 3 scanners passed |
| Last updated | August 2, 2026 |
| Repository | athola/claude-night-market ↗ |
What it does
Drop interactive GitHub (and similar) authentication with caching into bash workflow skills so commands fail fast with clear prompts.
Who is it for?
Best when you're maintaining bash-based agent commands in Leyline-style plugins and want one reusable auth module instead of per-script checks.
Skip if: Pure in-app OAuth flows or languages that never shell out to gh-style CLIs without adapting the bash module.
When should I use this skill?
At the start of any bash workflow or agent command that requires GitHub or external CLI authentication.
What you get
Workflows source ensure_auth helpers so users get guided login, cached auth for repeat commands, and reliable execution in local and token-based CI runs.
- Reusable ensure_auth integration in command scripts
- Documented before/after patterns for PR review and issue creation flows
By the numbers
- Auth status cached for 5 minutes
- Session persistence up to 24 hours
Files
Table of Contents
- Overview
- When to Use
- Authentication Methods
- Quick Start
- Verify Authentication
- Smoke Test
- Standard Flow
- Step 1: Check Environment
- Step 2: Verify with Service
- Step 3: Handle Failures
- Integration Pattern
- Detailed Resources
- Exit Criteria
Authentication Patterns
Overview
Common authentication patterns for integrating with external services. Provides consistent approaches to credential management, verification, and error handling.
When To Use
- Integrating with external APIs
- Need credential verification
- Managing multiple auth methods
- Handling auth failures gracefully
When NOT To Use
- Project doesn't use the leyline infrastructure patterns
- Simple scripts without service architecture needs
Authentication Methods
| Method | Best For | Environment Variable |
|---|---|---|
| API Key | Simple integrations | {SERVICE}_API_KEY |
| OAuth | User-authenticated | Browser-based flow |
| Token | Session-based | {SERVICE}_TOKEN |
| None | Public APIs | N/A |
Quick Start
Verify Authentication
from leyline.auth import verify_auth, AuthMethod
# API Key verification
status = verify_auth(
service="gemini",
method=AuthMethod.API_KEY,
env_var="GEMINI_API_KEY"
)
if not status.authenticated:
print(f"Auth failed: {status.message}")
print(f"Action: {status.suggested_action}")Verification: Run the command with --help flag to verify availability.
Smoke Test
def verify_with_smoke_test(service: str) -> bool:
"""Verify auth with simple request."""
result = execute_simple_request(service, "ping")
return result.successVerification: Run pytest -v to verify tests pass.
Standard Flow
Step 1: Check Environment
def check_credentials(service: str, env_var: str) -> bool:
value = os.getenv(env_var)
if not value:
print(f"Missing {env_var}")
return False
return TrueVerification: Run the command with --help flag to verify availability.
Step 2: Verify with Service
def verify_with_service(service: str) -> AuthStatus:
result = subprocess.run(
[service, "auth", "status"],
capture_output=True
)
return AuthStatus(
authenticated=(result.returncode == 0),
message=result.stdout.decode()
)Verification: Run the command with --help flag to verify availability.
Step 3: Handle Failures
def handle_auth_failure(service: str, method: AuthMethod) -> str:
actions = {
AuthMethod.API_KEY: f"Set {service.upper()}_API_KEY environment variable",
AuthMethod.OAUTH: f"Run '{service} auth login' for browser auth",
AuthMethod.TOKEN: f"Refresh token with '{service} token refresh'"
}
return actions[method]Verification: Run the command with --help flag to verify availability.
Integration Pattern
# In your skill's frontmatter
dependencies: [leyline:authentication-patterns]Verification: Run the command with --help flag to verify availability.
Interactive Authentication (Shell)
For workflows requiring interactive authentication with token caching and session management:
# Source the interactive auth script
source plugins/leyline/scripts/interactive_auth.sh
# Ensure authentication before proceeding
ensure_auth github || exit 1
ensure_auth gitlab || exit 1
ensure_auth aws || exit 1
# Continue with authenticated operations
gh pr view 123
glab issue list
aws s3 lsFeatures:
- ✅ Interactive OAuth flows for GitHub, GitLab, AWS, and more
- ✅ Token caching (5-minute TTL)
- ✅ Session persistence (24-hour TTL)
- ✅ CI/CD compatible (auto-detects non-interactive environments)
- ✅ Multi-service support
See modules/interactive-auth.md for complete documentation.
Detailed Resources
- Auth Methods: See
modules/auth-methods.mdfor method details - Verification: See
modules/verification-patterns.mdfor testing patterns - Interactive: See
modules/interactive-auth.mdfor shell-based auth flows
Exit Criteria
- Credentials verified or clear failure message
- Suggested action for auth failures
- Smoke test confirms working auth
Workflow Integration Examples
Examples of integrating the interactive authentication module into existing workflows.
Pattern: Pre-Flight Authentication Check
Add authentication check at the start of any workflow requiring external service access.
Before: Manual Auth Check
# Old way - manual check, unclear error handling
if ! gh auth status &>/dev/null; then
echo "Error: Not authenticated"
echo "Run: gh auth login"
exit 1
fi
gh pr view 123After: Interactive Auth with Caching
# New way - interactive auth with caching
source plugins/leyline/scripts/interactive_auth.sh
ensure_auth github || exit 1
gh pr view 123Example 1: PR Review Command
#!/usr/bin/env bash
# /pr-review command
# Source interactive auth
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Ensure GitHub authentication
if ! ensure_auth github; then
echo "❌ GitHub authentication required for PR review"
exit 1
fi
# Get PR number
PR_NUMBER="${1:-$(gh pr view --json number -q .number)}"
# Continue with workflow
echo "Reviewing PR #$PR_NUMBER..."
gh pr view "$PR_NUMBER"
gh api "repos/owner/repo/pulls/$PR_NUMBER/comments"Benefits:
- ✅ User is prompted to authenticate if needed
- ✅ Auth status cached for 5 minutes
- ✅ Session persists for 24 hours
- ✅ Works in CI/CD with
GITHUB_TOKEN
Example 2: Create Issue Command
#!/usr/bin/env bash
# /create-issue command
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Ensure authentication
if ! ensure_auth github; then
echo "❌ GitHub authentication required to create issues"
exit 1
fi
# Parse arguments
TITLE="$1"
shift
# Create issue
gh issue create --title "$TITLE" "$@"Example 3: Multi-Service Workflow
#!/usr/bin/env bash
# Sync issues from GitHub to GitLab
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Authenticate both services
ensure_auth github || exit 1
ensure_auth gitlab || exit 1
# Sync issues
gh issue list --json number,title | \
jq -r '.[] | "\(.number)|\(.title)"' | \
while IFS='|' read -r num title; do
glab issue create --title "gh-$num: $title"
doneExample 4: Batch Operations with Wrapper Functions
#!/usr/bin/env bash
# Batch PR operations
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Use wrapper functions for cleaner code
gh_api_with_auth "repos/owner/repo/pulls" | \
jq -r '.[].number' | \
while read -r pr_num; do
gh_with_auth pr view "$pr_num"
doneExample 5: CI/CD Pipeline Integration
# .github/workflows/pr-review.yml
name: PR Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Install Claude Code plugins
run: |
# Plugin setup here
:
- name: Run PR Review
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AUTH_INTERACTIVE: false # Force non-interactive mode
run: |
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Will use GITHUB_TOKEN from environment
if ! ensure_auth github; then
echo "GitHub authentication failed"
exit 1
fi
# Run review
/pr-review ${{ github.event.pull_request.number }}Key Points:
AUTH_INTERACTIVE=falseforces non-interactive modeGITHUB_TOKENis used automatically (GitHub Actions provides it)- No browser prompts in CI/CD environment
Example 6: Fix PR Command Integration
#!/usr/bin/env bash
# /fix-pr command
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Ensure authentication before starting workflow
if ! ensure_auth github; then
cat << 'EOF'
❌ GitHub Authentication Required
This workflow requires GitHub API access to:
- Fetch PR details and review comments
- Post replies to review threads
- Resolve review threads
- Create issues for deferred items
Please authenticate to continue.
EOF
exit 1
fi
# Continue with workflow
PR_NUMBER="${1:-$(gh pr view --json number -q .number)}"
echo "Processing PR #$PR_NUMBER..."
# ... rest of workflowMigration Checklist
When updating existing workflows to use interactive auth:
- [ ] Add
sourceline at the top of the script - [ ] Replace
gh auth statuschecks withensure_auth github - [ ] Add informative error messages if auth fails
- [ ] Test interactive authentication flow
- [ ] Test CI/CD compatibility with
AUTH_INTERACTIVE=false - [ ] Update workflow documentation
Advanced: Custom Cache Configuration
#!/usr/bin/env bash
# Long-running workflow with extended cache
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Extend cache to 1 hour for long-running workflow
export AUTH_CACHE_TTL=3600
# Initial authentication
ensure_auth github || exit 1
# ... operations that take a long time ...
# Later in workflow - uses cached auth (fast)
ensure_auth github # Skips check if within 1 hourError Handling Pattern
#!/usr/bin/env bash
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Wrapper for error handling
run_authenticated_command() {
local service="$1"
shift
if ! ensure_auth "$service"; then
return 1
fi
"$@"
}
# Usage
if ! run_authenticated_command github gh pr view 123; then
echo "Failed to fetch PR details"
exit 1
fiTesting the Integration
Test Interactive Flow
# 1. Ensure not authenticated
gh auth logout || true
clear_all_auth_cache
# 2. Run workflow - should prompt for auth
/test-workflow.sh
# 3. Verify session created
cat ~/.cache/claude-auth/github/session.json
# 4. Run again - should use session (no prompt)
/test-workflow.shTest CI/CD Flow
# Test non-interactive mode
export AUTH_INTERACTIVE=false
export GITHUB_TOKEN="ghp_..."
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
ensure_auth github # Should use GITHUB_TOKEN, no promptTest Cache Expiration
# Set short TTL for testing
export AUTH_CACHE_TTL=10
ensure_auth github # Initial auth
ensure_auth github # Uses cache (fast)
sleep 11
ensure_auth github # Cache expired, re-validatesBenefits Summary
| Aspect | Before | After |
|---|---|---|
| User Experience | Silent failure or manual instructions | Interactive OAuth prompt |
| Caching | No caching | 5-minute auth cache |
| Sessions | No persistence | 24-hour session |
| CI/CD Support | Manual env var setup | Auto-detects and uses env vars |
| Multi-Service | Separate checks for each | Unified interface |
| Error Messages | Generic errors | Clear, actionable messages |
Authentication Methods
API Key Authentication
Setup
# Set in environment
export GEMINI_API_KEY="your-key-here"
# Or in .env file
echo "GEMINI_API_KEY=your-key-here" >> ~/.envVerification
def verify_api_key(env_var: str) -> AuthStatus:
key = os.getenv(env_var)
if not key:
return AuthStatus(
authenticated=False,
message=f"Missing {env_var}",
suggested_action=f"Set {env_var} environment variable"
)
# Validate format (basic check)
if len(key) < 20:
return AuthStatus(
authenticated=False,
message="API key appears invalid (too short)",
suggested_action="Verify API key is correct"
)
return AuthStatus(authenticated=True)OAuth Authentication
Browser Flow
def initiate_oauth(service: str) -> AuthStatus:
"""Start OAuth browser flow."""
result = subprocess.run(
[service, "auth", "login"],
capture_output=True
)
if result.returncode == 0:
return AuthStatus(
authenticated=True,
message="OAuth completed successfully"
)
return AuthStatus(
authenticated=False,
message="OAuth flow failed",
suggested_action="Check browser, try incognito mode"
)Token Storage
# OAuth tokens typically stored by CLI
# Common locations:
# ~/.config/{service}/credentials.json
# ~/.{service}/auth.jsonToken Authentication
Token Refresh
def refresh_token(service: str) -> AuthStatus:
"""Refresh expired token."""
result = subprocess.run(
[service, "token", "refresh"],
capture_output=True
)
if result.returncode == 0:
return AuthStatus(authenticated=True)
# Token refresh failed, need re-auth
return AuthStatus(
authenticated=False,
message="Token refresh failed",
suggested_action=f"Run '{service} auth login' to re-authenticate"
)Token Validation
def validate_token(token: str) -> bool:
"""Basic token validation."""
try:
# JWT tokens have 3 parts
parts = token.split(".")
if len(parts) == 3:
return True
except:
pass
return FalseMulti-Method Secondary
def authenticate(service: str, methods: list[AuthMethod]) -> AuthStatus:
"""Try multiple auth methods in order."""
for method in methods:
status = verify_auth(service, method)
if status.authenticated:
return status
return AuthStatus(
authenticated=False,
message="All authentication methods failed",
suggested_action="Check credentials and try again"
)Interactive Authentication
Overview
Provides interactive authentication flows for external services with automatic token caching, session management, and multi-service support.
Authenticate Once, Use Everywhere: Tokens are cached locally and validated efficiently, minimizing interactive prompts while maintaining security.
CI/CD Compatible: Automatically detects non-interactive environments and falls back to environment variables.
Quick Start
source plugins/leyline/scripts/interactive_auth.sh
ensure_auth github || exit 1
gh pr view 123Configuration
Environment Variables
| Variable | Purpose | Default |
|---|---|---|
AUTH_CACHE_DIR | Token cache directory | ~/.cache/claude-auth |
AUTH_CACHE_TTL | Cache TTL in seconds | 300 (5 min) |
AUTH_SESSION_TTL | Session persistence TTL | 86400 (24 hr) |
AUTH_INTERACTIVE | Force interactive mode | auto (detect) |
AUTH_MAX_ATTEMPTS | Max authentication attempts | 3 |
Service-Specific Variables
export GITHUB_TOKEN="..." # GitHub fallback
export GITLAB_TOKEN="..." # GitLab
export AWS_ACCESS_KEY_ID="..." # AWS
export AWS_SECRET_ACCESS_KEY="..."
export GOOGLE_APPLICATION_CREDENTIALS="path/to/credentials.json"Core Functions
ensure_auth <service>
Ensure authentication for a service, prompting if necessary. Returns 0 on success, 1 on failure.
ensure_auth github || exit 1
ensure_auth gitlab || exit 1
ensure_auth aws || exit 1Supported services: github (gh), gitlab (glab), aws, gcloud, azure
check_auth_status <service>
Non-interactive check. Returns 0 if authenticated, 1 otherwise.
if check_auth_status github; then
echo "GitHub is authenticated"
fiinvalidate_auth_cache <service>
Force re-authentication next time.
invalidate_auth_cache github
ensure_auth github # Will prompt againclear_all_auth_cache
Clear all cached authentication data across all services.
Token Caching
Cache structure:
~/.cache/claude-auth/
├── github/
│ ├── auth_status.json
│ ├── last_verified.txt
│ └── token_cache.json
├── gitlab/
└── config.jsonCache validation uses three mechanisms:
1. Time-based expiration (default: 5 minutes) 2. Session persistence (default: 24 hours) 3. Manual invalidation (via invalidate_auth_cache)
Within the cache TTL, ensure_auth returns immediately without contacting the service. After TTL expiry, it re-validates with the service. After session TTL expiry, full re-authentication is required.
Authentication Flows
GitHub
ensure_auth github checks gh auth status first, then cache, then prompts:
1. Browser OAuth (recommended) 2. Personal Access Token 3. Cancel workflow
AWS
ensure_auth aws checks aws sts get-caller-identity first, then prompts:
1. AWS Access Keys 2. SSO Session 3. Web Identity (OIDC) 4. Cancel workflow
Other Services
GitLab uses glab auth login, GCP uses gcloud auth login, Azure uses az login. All follow the same check-cache-prompt pattern.
CI/CD Compatibility
The module auto-detects non-interactive environments ($CI, $GITHUB_ACTIONS, or non-terminal stdin) and falls back to environment variables.
# .github/workflows/pr-review.yml
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run PR review
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AUTH_INTERACTIVE: false
run: |
source plugins/leyline/scripts/interactive_auth.sh
ensure_auth github || exit 1
/pr-review ${{ github.event.pull_request.number }}Error Handling
Failed authentications retry with exponential backoff (2, 4, 8 seconds) up to AUTH_MAX_ATTEMPTS.
| Error | Cause | Solution |
|---|---|---|
gh: command not found | CLI not installed | Install via package manager |
gh auth status: failed | Not authenticated | Run gh auth login or set GITHUB_TOKEN |
Token expired | Cached token expired | Re-authenticate via ensure_auth |
Invalid credentials | Wrong token/keys | Verify in service dashboard |
Troubleshooting
Auth not working after changing credentials:
clear_all_auth_cache
ensure_auth githubKeeps asking for authentication:
export AUTH_SESSION_TTL=604800 # Extend to 7 days
ensure_auth githubFails in CI with "not a terminal":
export AUTH_INTERACTIVE=false
export GITHUB_TOKEN="..."
ensure_auth githubSecurity Considerations
1. Token storage: Managed by service CLIs, not this module (e.g., ~/.config/gh/hosts.yml) 2. Cache permissions: Directory restricted to 0700 3. No token logging: Tokens are never logged or echoed 4. Session expiration: Limits credential lifetime 5. CI/CD best practice: Use short-lived tokens
Exit Criteria
- Service is authenticated (via CLI or token)
- Session is cached for future use
- Workflow can proceed with API access
- CI/CD environments use environment variables
Verification Patterns
Smoke Test
Simple Request Test
def smoke_test(service: str) -> bool:
"""Test auth with minimal request."""
try:
result = subprocess.run(
[service, "-p", "Respond with OK"],
capture_output=True,
timeout=30
)
return result.returncode == 0
except subprocess.TimeoutExpired:
return FalseModel Access Test
def test_model_access(service: str, model: str) -> bool:
"""Verify access to specific model."""
result = subprocess.run(
[service, "--model", model, "-p", "ping"],
capture_output=True
)
return result.returncode == 0Pre-Flight Checks
Full Verification Flow
def preflight_auth_check(service: str) -> dict:
"""Complete auth verification before operations."""
checks = {
"env_var_set": False,
"cli_available": False,
"auth_valid": False,
"model_access": False
}
# Check environment variable
env_var = f"{service.upper()}_API_KEY"
checks["env_var_set"] = bool(os.getenv(env_var))
# Check CLI available
checks["cli_available"] = shutil.which(service) is not None
# Check auth status
if checks["cli_available"]:
result = subprocess.run([service, "auth", "status"], capture_output=True)
checks["auth_valid"] = result.returncode == 0
# Check model access
if checks["auth_valid"]:
checks["model_access"] = smoke_test(service)
return checksCached Verification
class AuthCache:
"""Cache auth status to avoid repeated checks."""
def __init__(self, ttl_seconds: int = 300):
self.cache = {}
self.ttl = ttl_seconds
def get_status(self, service: str) -> AuthStatus | None:
if service in self.cache:
status, timestamp = self.cache[service]
if time.time() - timestamp < self.ttl:
return status
return None
def set_status(self, service: str, status: AuthStatus):
self.cache[service] = (status, time.time())Error Diagnostics
def diagnose_auth_failure(service: str, error: str) -> list[str]:
"""Diagnose common auth failures."""
suggestions = []
if "401" in error or "unauthorized" in error.lower():
suggestions.append("API key may be invalid or expired")
suggestions.append(f"Verify {service.upper()}_API_KEY is correct")
if "403" in error or "forbidden" in error.lower():
suggestions.append("API key may lack required permissions")
suggestions.append("Check API key scopes in provider dashboard")
if "network" in error.lower() or "connection" in error.lower():
suggestions.append("Check network connectivity")
suggestions.append("Verify proxy settings if applicable")
return suggestionsAuthentication Patterns - Interactive OAuth
Interactive authentication for external services with automatic token caching, session management, and CI/CD support.
Quick Start
# Source the interactive auth script
source plugins/leyline/scripts/interactive_auth.sh
# Ensure authentication (prompts if needed)
ensure_auth github || exit 1
# Use service APIs
gh pr view 123
gh api repos/owner/repo/issuesFeatures
✅ Interactive OAuth - Browser-based authentication flow for GitHub, GitLab, AWS, and more ✅ Token Caching - 5-minute cache reduces redundant auth checks ✅ Session Management - 24-hour session persistence across workflow runs ✅ Multi-Service Support - Unified interface for GitHub, GitLab, AWS, GCP, Azure ✅ CI/CD Compatible - Auto-detects non-interactive environments ✅ Retry Logic - Exponential backoff for transient failures ✅ Secure - Tokens stored by service CLIs, never logged
Supported Services
| Service | CLI Tool | Auth Command |
|---|---|---|
| GitHub | gh | gh auth login |
| GitLab | glab | glab auth login |
| AWS | aws | aws configure |
| Google Cloud | gcloud | gcloud auth login |
| Azure | az | az login |
Note (Claude Code 2.1.41+):claude auth login,claude auth status, andclaude auth logoutmanage Claude API authentication. These are separate from the git platform auth commands above.
Installation
No installation required - the module is part of the leyline plugin.
Usage
Basic Authentication
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Check and prompt if needed
ensure_auth github || exit 1
ensure_auth gitlab || exit 1
ensure_auth aws || exit 1In Workflows
#!/usr/bin/env bash
# My workflow that uses GitHub API
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
# Ensure authentication at start
if ! ensure_auth github; then
echo "❌ GitHub authentication required"
exit 1
fi
# Continue with workflow
gh pr list
gh issue create --title "My Issue"Wrapper Functions
# Use wrapper functions for cleaner code
gh_with_auth pr view 123
gh_api_with_auth repos/owner/repo/pulls
glab_with_auth issue list
aws_with_auth s3 lsConfiguration
Environment Variables
| Variable | Purpose | Default |
|---|---|---|
AUTH_CACHE_DIR | Cache directory | ~/.cache/claude-auth |
AUTH_CACHE_TTL | Cache TTL (seconds) | 300 (5 min) |
AUTH_SESSION_TTL | Session TTL (seconds) | 86400 (24 hr) |
AUTH_INTERACTIVE | Force mode | auto (detect) |
AUTH_MAX_ATTEMPTS | Max retries | 3 |
Service-Specific Variables
# GitHub (fallback for CI/CD)
export GITHUB_TOKEN="ghp_..."
# GitLab
export GITLAB_TOKEN="glpat-..."
# AWS
export AWS_ACCESS_KEY_ID="..."
export AWS_SECRET_ACCESS_KEY="..."
export AWS_SESSION_TOKEN="..." # For temp credentialsHow It Works
Authentication Flow
1. Check cache (fast)
└─> Valid? → Return success
2. Check session (medium)
└─> Valid? → Verify auth status
└─> Valid? → Return success
3. Full auth check (slow)
└─> Valid? → Create session, cache result
└─> Not valid? → Prompt user
4. Interactive prompt
└─> User authenticates
└─> Verify success
└─> Create session, cache result
└─> Return successCache Storage
~/.cache/claude-auth/
├── github/
│ ├── auth_status.json # Auth status + timestamp
│ ├── session.json # Session info (24hr TTL)
│ └── token_cache.json # Token metadata (optional)
├── gitlab/
│ └── ...
└── config.json # Global configInteractive Prompt Example
When authentication is needed, users see:
🔐 GitHub Authentication Required
This workflow needs GitHub API access to continue.
How would you like to authenticate?
1. Browser (OAuth) - Recommended
2. Personal Access Token
3. Cancel workflow
Choose [1-3]:Option 1 (OAuth): Opens browser for GitHub authorization Option 2 (Token): Paste personal access token directly Option 3: Cancel the workflow
CI/CD Integration
GitHub Actions Example
name: PR Review
on:
pull_request:
types: [opened, synchronize]
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run PR Review
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AUTH_INTERACTIVE: false # Force non-interactive
run: |
source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
ensure_auth github || exit 1
/pr-review ${{ github.event.pull_request.number }}GitLab CI Example
review:
script:
- export GITLAB_TOKEN="$CI_JOB_TOKEN"
- export AUTH_INTERACTIVE=false
- source plugins/leyline/skills/authentication-patterns/modules/interactive_auth.sh
- ensure_auth gitlab || exit 1
- ./run-review.shAPI Reference
Main Functions
ensure_auth <service>
Ensure authentication for a service, prompting if necessary.
Parameters:
service- Service name (github, gitlab, aws, gcloud, azure)
Returns:
0- Authentication successful1- Authentication failed
Example:
if ensure_auth github; then
echo "Authenticated!"
gh pr view 123
else
echo "Authentication failed"
exit 1
ficheck_auth_status <service>
Check if service is authenticated (non-interactive).
Parameters:
service- Service name
Returns:
0- Authenticated1- Not authenticated
Example:
if check_auth_status github; then
echo "GitHub is authenticated"
else
echo "Need to authenticate"
fiinvalidate_auth_cache <service>
Invalidate cached authentication status.
Parameters:
service- Service name
Example:
invalidate_auth_cache github
ensure_auth github # Will re-checkclear_all_auth_cache
Clear all cached authentication data.
Example:
clear_all_auth_cacheWrapper Functions
gh_with_auth [args...]
Run gh command with automatic authentication.
Example:
gh_with_auth pr view 123
gh_with_auth issue listgh_api_with_auth <endpoint>
Run gh api with automatic authentication.
Example:
gh_api_with_auth "repos/owner/repo/issues"
gh_api_with_auth "repos/owner/repo/pulls/123"Advanced Usage
Custom Cache Configuration
# Extend cache to 1 hour
export AUTH_CACHE_TTL=3600
ensure_auth github
# Disable caching
export AUTH_CACHE_TTL=0
ensure_auth githubForce Interactive Mode
# Force prompts even if terminal detection fails
export AUTH_INTERACTIVE=true
ensure_auth githubForce Non-Interactive Mode
# Disable prompts (fail if not authenticated)
export AUTH_INTERACTIVE=false
ensure_auth github || exit 1Multi-Service Workflows
# Authenticate multiple services
ensure_auth github || exit 1
ensure_auth gitlab || exit 1
ensure_auth aws || exit 1
# Use all services
gh pr list
glab issue list
aws s3 lsTroubleshooting
"gh: command not found"
Problem: GitHub CLI is not installed.
Solution:
# macOS
brew install gh
# Linux
sudo apt install gh # Ubuntu/Debian
sudo yum install gh # RHEL/CentOS
# Verify installation
gh --version"Authentication failed"
Problem: OAuth flow or token authentication failed.
Solution:
# Clear cache and retry
clear_all_auth_cache
ensure_auth github
# Or use token manually
echo "your_token" | gh auth login --with-token"Keeps asking for authentication"
Problem: Session not persisting.
Solution:
# Check session file
cat ~/.cache/claude-auth/github/session.json
# Extend session TTL
export AUTH_SESSION_TTL=604800 # 7 days
ensure_auth github"Not working in CI/CD"
Problem: CI/CD environment requires non-interactive mode.
Solution:
# Set environment variable
export AUTH_INTERACTIVE=false
export GITHUB_TOKEN="..." # Your token
ensure_auth githubSecurity Considerations
1. Token Storage - Tokens stored by service CLIs, not this module
- GitHub:
~/.config/gh/hosts.yml - GitLab:
~/.config/glab/config.yml - AWS:
~/.aws/credentials
2. Cache Permissions - Cache directory has restricted permissions (0700)
3. No Logging - Tokens never logged or echoed
4. Session Expiration - Sessions expire to limit credential lifetime
5. CI/CD Best Practice - Use short-lived tokens in CI/CD environments
Examples
See examples/workflow-integration.md for complete examples:
- PR Review command integration
- Create Issue command integration
- Multi-service workflows
- CI/CD pipelines
- Error handling patterns
Contributing
To add support for a new service:
1. Add to AUTH_CHECK_COMMANDS array in interactive_auth.sh 2. Add to AUTH_LOGIN_COMMANDS array 3. Create prompt function if needed (e.g., prompt_newservice_auth) 4. Add documentation to this README
Example:
# In interactive_auth.sh
declare -A AUTH_CHECK_COMMANDS=(
...
[myservice]="myservice auth status"
)
declare -A AUTH_LOGIN_COMMANDS=(
...
[myservice]="myservice auth login"
)License
Part of the claude-night-market ecosystem.
See Also
- Authentication Patterns Skill - Main skill documentation
- Interactive Auth Module - Detailed module docs
- Workflow Integration Examples - Integration patterns
- Auth Methods - Authentication method details
- Verification Patterns - Testing patterns
#!/usr/bin/env bash
#
# Test script for interactive authentication module
# Demonstrates basic functionality without requiring actual authentication
#
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo "========================================"
echo "Interactive Auth Module Test Suite"
echo "========================================"
echo ""
# Source the module
# Get the repository root by going up from tests directory
TEST_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Find leyline plugin root (contains scripts/ directory)
LEYLINE_ROOT="$(cd "$TEST_DIR/../../.." && pwd)"
MODULE_PATH="$LEYLINE_ROOT/scripts/interactive_auth.sh"
if [[ ! -f "$MODULE_PATH" ]]; then
echo -e "${RED}✗ Module not found: $MODULE_PATH${NC}"
exit 1
fi
echo -e "${GREEN}✓ Module file exists${NC}"
# Test 1: Syntax check
echo ""
echo "Test 1: Syntax validation"
if bash -n "$MODULE_PATH"; then
echo -e "${GREEN}✓ Syntax is valid${NC}"
else
echo -e "${RED}✗ Syntax errors found${NC}"
exit 1
fi
# Test 2: Source module
echo ""
echo "Test 2: Source module"
if source "$MODULE_PATH"; then
echo -e "${GREEN}✓ Module sourced successfully${NC}"
else
echo -e "${RED}✗ Failed to source module${NC}"
exit 1
fi
# Test 3: Check function availability
echo ""
echo "Test 3: Function availability"
functions=(
"ensure_auth"
"check_auth_status"
"invalidate_auth_cache"
"clear_all_auth_cache"
"is_interactive"
"is_ci"
)
all_found=true
for func in "${functions[@]}"; do
if declare -f "$func" > /dev/null; then
echo -e " ${GREEN}✓${NC} $func"
else
echo -e " ${RED}✗${NC} $func (not found)"
all_found=false
fi
done
if [[ "$all_found" == "true" ]]; then
echo -e "${GREEN}✓ All functions available${NC}"
else
echo -e "${RED}✗ Some functions missing${NC}"
exit 1
fi
# Test 4: Check cache directory creation
echo ""
echo "Test 4: Cache directory initialization"
TEST_CACHE_DIR="/tmp/test-auth-cache-$$"
export AUTH_CACHE_DIR="$TEST_CACHE_DIR"
init_cache_dir "github"
if [[ -d "$TEST_CACHE_DIR/github" ]]; then
echo -e "${GREEN}✓ Cache directory created${NC}"
else
echo -e "${RED}✗ Failed to create cache directory${NC}"
exit 1
fi
# Test 5: Cache write and read
echo ""
echo "Test 5: Cache write and read"
write_cache "github" "true"
if [[ -f "$TEST_CACHE_DIR/github/auth_status.json" ]]; then
echo -e "${GREEN}✓ Cache file created${NC}"
else
echo -e "${RED}✗ Failed to create cache file${NC}"
exit 1
fi
# Test 6: Cache validation
echo ""
echo "Test 6: Cache validation"
if check_cache "github"; then
echo -e "${GREEN}✓ Cache validation works${NC}"
else
echo -e "${RED}✗ Cache validation failed${NC}"
exit 1
fi
# Test 7: Session creation
echo ""
echo "Test 7: Session creation"
create_session "github"
if [[ -f "$TEST_CACHE_DIR/github/session.json" ]]; then
echo -e "${GREEN}✓ Session file created${NC}"
else
echo -e "${RED}✗ Failed to create session file${NC}"
exit 1
fi
# Test 8: Session validation
echo ""
echo "Test 8: Session validation"
if load_session "github"; then
echo -e "${GREEN}✓ Session validation works${NC}"
else
echo -e "${RED}✗ Session validation failed${NC}"
exit 1
fi
# Test 9: Cache invalidation
echo ""
echo "Test 9: Cache invalidation"
invalidate_auth_cache "github" > /dev/null 2>&1
if [[ ! -f "$TEST_CACHE_DIR/github/auth_status.json" ]]; then
echo -e "${GREEN}✓ Cache invalidated${NC}"
else
echo -e "${RED}✗ Cache invalidation failed${NC}"
exit 1
fi
# Test 10: Clear all caches
echo ""
echo "Test 10: Clear all caches"
clear_all_auth_cache > /dev/null 2>&1
if [[ ! -d "$TEST_CACHE_DIR" ]]; then
echo -e "${GREEN}✓ All caches cleared${NC}"
else
echo -e "${RED}✗ Failed to clear all caches${NC}"
exit 1
fi
# Test 11: Interactive detection
echo ""
echo "Test 11: Interactive mode detection"
export AUTH_INTERACTIVE=true
if is_interactive; then
echo -e "${GREEN}✓ Interactive mode detected (forced)${NC}"
else
echo -e "${YELLOW}⚠ May not be a TTY${NC}"
fi
export AUTH_INTERACTIVE=false
if ! is_interactive; then
echo -e "${GREEN}✓ Non-interactive mode detected (forced)${NC}"
else
echo -e "${RED}✗ Interactive mode should be false${NC}"
exit 1
fi
# Test 12: CI/CD detection
echo ""
echo "Test 12: CI/CD environment detection"
unset CI GITHUB_ACTIONS GITLAB_CI AWS_EXECUTION_ENV
if ! is_ci; then
echo -e "${GREEN}✓ Correctly detected non-CI environment${NC}"
else
echo -e "${YELLOW}⚠ Running in CI environment${NC}"
fi
export CI=true
if is_ci; then
echo -e "${GREEN}✓ CI environment detected${NC}"
else
echo -e "${RED}✗ Failed to detect CI environment${NC}"
exit 1
fi
unset CI
# Test 13: Unsupported service error handling
echo ""
echo "Test 13: Unsupported service error handling"
if ensure_auth "unsupported_service" 2>/dev/null; then
echo -e "${RED}✗ Should have failed for unsupported service${NC}"
exit 1
else
echo -e "${GREEN}✓ Correctly rejected unsupported service${NC}"
fi
# Test 14: Usage validation
echo ""
echo "Test 14: Usage validation"
if ensure_auth 2>/dev/null; then
echo -e "${RED}✗ Should have failed with no arguments${NC}"
exit 1
else
echo -e "${GREEN}✓ Correctly rejected missing service argument${NC}"
fi
# Cleanup
echo ""
echo "Cleanup"
rm -rf "$TEST_CACHE_DIR" 2>/dev/null || true
echo -e "${GREEN}✓ Test artifacts cleaned up${NC}"
# Summary
echo ""
echo "========================================"
echo -e "${GREEN}All tests passed!${NC}"
echo "========================================"
echo ""
echo "Module is ready for use in workflows."
echo ""
echo "Quick start:"
echo " source plugins/leyline/scripts/interactive_auth.sh"
echo " ensure_auth github || exit 1"
echo " gh pr view 123"
echo ""
Related skills
How it compares
Use as a workflow template layer, not a hosted identity provider or MCP auth server.
FAQ
Who is authentication-patterns for?
Developers wiring Claude Night Market / Leyline bash commands that need GitHub or similar CLI access with interactive fallback.
When should I use authentication-patterns?
Use it in Build (integrations) when authoring PR or issue commands; in Ship (review) before gh pr view or API calls; in Operate when automation scripts need GITHUB_TOKEN in CI.
Is authentication-patterns safe to install?
It runs shell auth helpers and may prompt for credentials; review the Security Audits panel on this page and scope tokens to least privilege.