Overview
This vignette covers advanced authentication topics for meetupr users who need:
- Higher API rate limits
- Production applications with their own OAuth credentials
- Fine-grained control over authentication flow
- Credential management across teams or environments
For basic usage, see the Getting Started vignette. Most users don’t need custom OAuth credentials and can use the package’s built-in authentication.
Why Use Custom OAuth Credentials
The meetupr package includes built-in OAuth credentials that work for most users. However, you should consider registering your own OAuth application if:
-
Rate limits: You’re hitting the default rate limit
(500 requests per 60 seconds) and need higher throughput
-
Production apps: You’re building a Shiny app, API,
or other production service that uses meetupr
-
Team usage: Multiple people share API access and
you want centralized credential management
-
Compliance: Your organization requires using OAuth
apps registered under your account
- Analytics: You want detailed usage analytics from the Meetup developer dashboard
Custom credentials don’t provide access to different data, only better control over how authentication is managed.
Registering a Meetup OAuth Application
Step 1: Create the OAuth App
Navigate to the Meetup OAuth app registration page:
https://www.meetup.com/api/oauth/list/
Click Create New OAuth Consumer and fill in the required fields:
-
Consumer Name: A descriptive name (e.g., “My R
Analysis App”)
-
Application Website: Your organization’s website or
GitHub repository
-
Redirect URI:
http://localhost:1410/(required for OAuth flow in R)
- Consumer Description: Brief description of what your app does
Step 2: Note Your Credentials
After creating the app, you’ll receive:
-
Key (Client ID): A unique identifier for your
application
- Secret (Client Secret): A confidential string used to authenticate your app
Important: Keep the client secret confidential. Never commit it to version control or share it publicly. Anyone with your secret can make API requests as your application.
Step 3: Understand OAuth Scopes
Meetup’s API uses scopes to control what data your application can access. The meetupr package requests these scopes by default:
-
basic: Read basic profile information
-
event_management: Read event data and RSVPs
-
group_join: Read group membership information
You can customize scopes when creating your OAuth app, but the defaults work for most meetupr use cases.
Storing Custom Credentials
meetupr uses the keyring package to securely store credentials in your system’s native credential manager.
Using the Keyring
Store your custom credentials:
# Store client ID and secret
meetup_key_set("client_id", "your_client_id_here")
meetup_key_set("client_secret", "your_client_secret_here")If you don’t provide values, you’ll be prompted interactively:
# Prompts for input
meetup_key_set("client_id")The credentials are stored securely in:
-
macOS: Keychain
-
Windows: Credential Manager
- Linux: Secret Service API (via libsecret)
Verifying Stored Credentials
Check what credentials are available:
# Check if credentials exist
key_available("client_id")
key_available("client_secret")
# Retrieve stored values (for debugging only - don't print secrets!)
client_id <- meetup_key_get("client_id")
# Note: Never print client_secret in logs or consoleRetrieving Credentials
meetupr automatically retrieves credentials from keyring when needed. The lookup order is:
- System keyring (via
meetup_key_get())
- Environment variables (
MEETUP_CLIENT_ID,MEETUP_CLIENT_SECRET)
- Built-in package credentials (fallback)
This allows you to override credentials at different levels (system-wide, project-specific, or per-session).
Authenticating with Custom Credentials
Once credentials are stored, authentication works the same as with built-in credentials:
# Authenticate (will use stored credentials automatically)
meetup_auth()
# Verify authentication
meetup_auth_status()The OAuth flow opens a browser where you:
- Log in with your Meetup account
- Grant permission to your registered OAuth app
- Get redirected back to R with an access token
The token is cached locally and reused until it expires (typically 90 days).
Using Environment Variables
For project-specific configurations, you can use environment
variables instead of keyring. Create a .Renviron file in
your project:
MEETUP_CLIENT_ID=your_client_id
MEETUP_CLIENT_SECRET=your_client_secret
Important: Add .Renviron to
.gitignore to avoid committing secrets.
Environment variables take precedence over keyring, allowing per-project overrides.
Using a Custom Client Name
By default, tokens are cached under the service name
"meetupr". If you’re using multiple OAuth apps, you can
specify a custom client name:
# Store credentials for a specific app
meetup_key_set("client_id", "app1_client_id")
meetup_key_set("client_secret", "app1_secret")
# Authenticate with custom client name
meetup_auth(client_name = "my_custom_app")
# Use the custom client for API calls
get_group("rladies-lagos", client_name = "my_custom_app")This allows you to maintain separate authentication for different projects or OAuth applications.
Advanced CI/CD Authentication
For production deployments, automated workflows, or team environments, you need non-interactive authentication.
Understanding CI Authentication Flow
The CI authentication pattern:
-
Locally (one-time setup): Authenticate
interactively and encode the token
-
CI Environment: Store the encoded token as a
secret
- CI Runtime: Decode and use the token without browser interaction
This lets automated systems use your OAuth credentials without exposing the client secret.
Setting Up CI Authentication
Step 1: Authenticate Locally
# First, ensure custom credentials are stored
meetup_key_set("client_id", "your_client_id")
meetup_key_set("client_secret", "your_client_secret")
# Authenticate interactively
meetup_auth()
# Generate CI credentials
meetup_ci_setup()The meetup_ci_setup() function will:
- Read your cached OAuth token
- Encode it as base64
- Store it in keyring under
"token"and"token_file"keys
- Display the values for setting CI secrets
- Provide platform-specific instructions
Output example:
Setting up CI credentials...
Add these secrets to your CI environment:
meetupr:token:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
meetupr:token_file:
ae743e0fbd718c21f2cca632e77bd180-token.rds.enc
GitHub Actions:
Settings > Secrets and variables > Actions > New repository secret
Name: MEETUPR_TOKEN (value: meetupr:token above)
Name: MEETUPR_TOKEN_FILE (value: meetupr:token_file above)
Step 2: Configure CI Secrets
GitHub Actions:
Go to repository Settings > Secrets and variables > Actions, then add:
-
MEETUPR_TOKEN: Base64-encoded token (the long string)
-
MEETUPR_TOKEN_FILE: Token filename (e.g.,ae743e0-token.rds.enc)
GitLab CI:
Go to Settings > CI/CD > Variables, then add:
-
MEETUPR_TOKEN: Base64-encoded token (mask variable)
-
MEETUPR_TOKEN_FILE: Token filename
Other CI platforms:
Most platforms have a secrets management feature. Store both values as environment variables that will be available at runtime.
Step 3: Load Token in CI Workflow
Add this to the beginning of your CI script:
# At the start of your CI script
meetup_ci_load()
# Now you can use the API
groups <- get_pro_groups("rladies")For GitHub Actions, your workflow YAML should include:
name: Meetup Data Analysis
on:
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
workflow_dispatch:
jobs:
analyze:
runs-on: ubuntu-latest
env:
"meetupr:token": ${{ secrets.MEETUPR_TOKEN }}
"meetupr:token_file": ${{ secrets.MEETUPR_TOKEN_FILE }}
steps:
- uses: actions/checkout@v3
- uses: r-lib/actions/setup-r@v2
- name: Install dependencies
run: |
install.packages(c("remotes", "meetupr"))
shell: Rscript {0}
- name: Run analysis
run: |
library(meetupr)
meetup_ci_load()
# Your analysis code here
groups <- get_pro_groups("rladies")
saveRDS(groups, "groups.rds")
shell: Rscript {0}
- name: Upload results
uses: actions/upload-artifact@v3
with:
name: analysis-results
path: groups.rdsImportant: Quote the environment variable names in YAML because they contain colons.
Token Expiration and Refresh
OAuth tokens typically expire after 90 days. When your CI workflow fails with authentication errors:
- Re-run
meetup_auth()locally to get a fresh token
- Run
meetup_ci_setup()to regenerate CI credentials
- Update the secrets in your CI platform with the new values
Consider setting up calendar reminders to refresh tokens before they expire.
Team Credential Management
For teams using shared CI credentials:
Option 1: Shared Keyring Credentials
Designate one person to:
- Register the OAuth app
- Store credentials in keyring
- Run CI setup and distribute secrets
- Refresh tokens when they expire
Option 2: Service Account
Create a dedicated Meetup account for API access:
- Register the account with a team email
- Grant it organizer access to relevant groups
- Register the OAuth app under this account
- Store credentials in team password manager
This centralizes management and doesn’t depend on individual team members’ accounts.
Option 3: Environment-Specific Apps
Register separate OAuth apps for different environments:
- Development: Individual developer credentials
- Staging: Shared staging app
- Production: Production-only app with restricted access
Use environment variables to switch between them:
# In .Renviron for each environment
MEETUP_CLIENT_ID=dev_client_id
MEETUP_CLIENT_SECRET=dev_secretCredential Security Best Practices
Do’s
- Store credentials in keyring or environment variables
- Add
.Renvironto.gitignore
- Use CI platform’s secrets management
- Rotate tokens periodically
- Use separate OAuth apps for dev/staging/production
- Limit scope to minimum required permissions
Don’ts
- Never commit credentials to version control
- Don’t share client secrets in plain text (Slack, email, etc.)
- Don’t print secrets in logs or console output
- Don’t use production credentials in development
- Don’t share OAuth tokens between applications
Credential Rotation
To rotate compromised credentials:
# 1. Delete old credentials from keyring
meetup_key_delete("client_id")
meetup_key_delete("client_secret")
meetup_key_delete("token")
meetup_key_delete("token_file")
# 2. Revoke the OAuth app on Meetup.com
# Go to https://www.meetup.com/api/oauth/list/
# Click "Revoke" on the compromised app
# 3. Create a new OAuth app (or regenerate secret)
# 4. Store new credentials
meetup_key_set("client_id", "new_client_id")
meetup_key_set("client_secret", "new_secret")
# 5. Re-authenticate
meetup_auth()
# 6. Update CI secrets
meetup_ci_setup()Audit Trail
Monitor your OAuth app usage:
- Visit https://www.meetup.com/api/oauth/list/
- Click on your app name
- View analytics and recent API usage
This helps detect unauthorized usage or unusual patterns.
Debugging Authentication Issues
Common Problems
Problem: meetup_auth() fails with
“invalid_client”
Solution: Verify client ID and secret are correct:
# Check stored values
client_id <- meetup_key_get("client_id")
print(client_id) # Should match OAuth app key
# Re-enter credentials if incorrect
meetup_key_set("client_id", "correct_client_id")
meetup_key_set("client_secret", "correct_secret")Problem: Token cached for wrong OAuth app
Solution: Clear cache and re-authenticate:
# Clear all authentication
meetup_deauth()
# Remove cached tokens
token_dir <- httr2::oauth_cache_path()
list.files(file.path(token_dir, "meetupr"))
# Delete specific token file if needed
# file.remove(file.path(
# token_dir,
# "meetupr",
# "token.rds.enc"
# ))
# Re-authenticate
meetup_auth()Problem: Multiple tokens warning
Solution: This happens when you’ve authenticated with different OAuth apps:
# See all cached tokens
token_dir <- httr2::oauth_cache_path()
list.files(file.path(token_dir, "meetupr"), pattern = "token.rds.enc$")
# Remove all tokens and start fresh
meetup_deauth()
meetup_auth()Problem: CI authentication fails
Solution: Verify environment variables are set correctly:
# Check if env vars are present
Sys.getenv("meetupr:token") # Should be long base64 string
Sys.getenv("meetupr:token_file") # Should be filename
# If empty, check CI platform secrets configuration
# Ensure quotes around variable names in YAML: "meetupr:token"Enable Debug Mode
For detailed authentication diagnostics:
# Enable debug mode
Sys.setenv(MEETUPR_DEBUG = "1")
# Run authentication
meetup_sitrep()
meetup_auth()
# Disable debug mode
Sys.setenv(MEETUPR_DEBUG = "0")Debug output shows:
- Credential lookup paths (keyring vs env vars)
- OAuth token cache location
- Request/response details
Inspect Token State
# Check authentication status
status <- meetup_auth_status()
print(status)
# Verify which credentials are being used
meetup_sitrep()Environment Variables Reference
Authentication Credentials
| Variable | Purpose | Example |
|---|---|---|
MEETUP_CLIENT_ID |
OAuth app client ID | ABC123XYZ |
MEETUP_CLIENT_SECRET |
OAuth app client secret | secret_key_here |
MEETUP_CLIENT_NAME |
Client name for token cache | my_app |
Keyring Functions Reference
Storing Credentials
# Store with explicit value
meetup_key_set("client_id", "your_value")
# Store with interactive prompt
meetup_key_set("client_secret")
# Valid key names: "client_id", "client_secret", "token", "token_file"Retrieving Credentials
# Get credential (errors if not found)
value <- meetup_key_get("client_id")
# Get credential (returns NULL if not found)
value <- meetup_key_get("client_id", error = FALSE)Checking Availability
# Check if key exists
if (key_available("client_id")) {
# Credential is stored
}Deleting Credentials
# Remove specific credential
meetup_key_delete("client_id")
# Or delete all with deauth
meetup_deauth()Complete CI/CD Example
Here’s a complete workflow for automated group analytics:
name: Weekly R-Ladies Analytics
on:
schedule:
- cron: '0 8 * * 1' # Monday at 8 AM UTC
workflow_dispatch:
jobs:
analyze:
runs-on: ubuntu-latest
env:
"meetupr:token": ${{ secrets.MEETUPR_TOKEN }}
"meetupr:token_file": ${{ secrets.MEETUPR_TOKEN_FILE }}
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Setup R
uses: r-lib/actions/setup-r@v2
with:
r-version: 'release'
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libcurl4-openssl-dev libssl-dev
- name: Install R packages
run: |
install.packages(c("remotes", "dplyr", "ggplot2"))
remotes::install_github("rladies/meetupr")
shell: Rscript {0}
- name: Load CI token
run: |
library(meetupr)
meetup_ci_load()
meetup_sitrep()
shell: Rscript {0}
- name: Fetch data
run: |
library(meetupr)
library(dplyr)
# Get all R-Ladies groups
groups <- get_pro_groups("rladies")
saveRDS(groups, "data/groups.rds")
# Get recent events
events <- get_pro_events("rladies", "past", max_results = 100)
saveRDS(events, "data/events.rds")
# Summary stats
summary <- events |>
group_by(group_urlname) |>
summarise(
total_events = n(),
avg_attendance = mean(going, na.rm = TRUE),
.groups = "drop"
)
write.csv(summary, "reports/summary.csv", row.names = FALSE)
shell: Rscript {0}
- name: Generate report
run: |
library(rmarkdown)
rmarkdown::render("reports/weekly_report.Rmd")
shell: Rscript {0}
- name: Commit results
run: |
git config --local user.name "GitHub Actions"
git config --local user.email "actions@github.com"
git add data/ reports/
git diff --quiet && git diff --staged --quiet || git commit -m "Update weekly analytics"
git pushThis workflow:
- Runs weekly on a schedule
- Loads CI credentials from secrets
- Fetches Pro group and event data
- Generates summary statistics
- Renders a report
- Commits results back to repository
Additional Resources
Official Documentation
-
Meetup OAuth Documentation: https://www.meetup.com/api/authentication/
-
OAuth App Management: https://www.meetup.com/api/oauth/list/
- API Rate Limits: https://www.meetup.com/api/general/
Related Vignettes
-
Getting Started: See
vignette("meetupr")for basic authentication and usage
-
Custom GraphQL Queries: See
vignette("graphql")for advanced API queries
Security Resources
-
OWASP OAuth 2.0 Security: https://oauth.net/2/security-considerations/
-
R Keyring Package: https://keyring.r-lib.org/
- GitHub Actions Secrets: https://docs.github.com/en/actions/security-guides/encrypted-secrets
Getting Help
For authentication issues:
-
Run diagnostics:
meetup_sitrep()shows authentication status
-
Enable debug mode:
Sys.setenv(MEETUPR_DEBUG = "1")
-
Check keyring: Verify credentials with
key_available()
-
Clear and retry:
meetup_deauth()thenmeetup_auth()
When reporting issues, include:
- Output from
meetup_sitrep()
- Whether you’re using custom credentials
- Authentication method (interactive vs CI)
- Platform (macOS, Windows, Linux)
- Never include actual tokens or secrets
For package updates and issues, visit the GitHub repository.
