This guide walks through creating an Okta API Services application for github-ops-app to sync Okta groups with GitHub teams.
- Okta organization with admin access
- Super Admin or Application Admin role
-
Log in to your Okta Admin Console
-
Navigate to Applications → Applications
-
Click Create App Integration
-
Select API Services and click Next
API Services apps use OAuth 2.0 client credentials flow with no user context, ideal for server-to-server integrations.
-
Enter application name:
github-ops-app(or similar) -
Click Save
After creating the app:
- Go to the General tab
- Under Client Credentials, click Edit
- Set Client authentication to Public key / Private key
- Click Save
- Under PUBLIC KEYS, click Add Key
- Click Generate new key
- Click Download PEM to save the private key
- Click Save
The downloaded file contains your private key for APP_OKTA_PRIVATE_KEY.
# Generate private key
openssl genpkey -algorithm RSA -out okta-private-key.pem -pkeyopt rsa_keygen_bits:2048
# Extract public key in JWK format (for Okta)
# You'll need to convert PEM to JWK - use a tool like:
# https://8gwifi.org/jwkconvertfunctions.jsp
# Or use the node jose libraryThen upload the public JWK to Okta under PUBLIC KEYS → Add Key.
On the General tab, find and save:
- Client ID - alphanumeric string (e.g.,
0oa1abc2def3ghi4j5k6)
-
Go to the Okta API Scopes tab
-
Grant the following scopes:
Scope Purpose okta.groups.readRead group names and members okta.users.readRead user profiles -
Click Grant for each scope
These scopes allow read-only access to groups and users - no write access to Okta is required.
Your Okta domain is the URL you use to access the admin console:
- Production:
your-org.okta.com - Preview/Dev:
your-org.oktapreview.comordev-123456.okta.com
Use the domain without https:// prefix for APP_OKTA_DOMAIN.
The app needs to map Okta users to GitHub usernames. Determine which Okta user profile field contains GitHub usernames:
| Common Fields | Description |
|---|---|
login |
Okta username (often email) |
email |
User's email address |
githubUsername |
Custom field (recommended) |
nickName |
Sometimes used for GitHub username |
- Go to Directory → Profile Editor
- Select Okta (or your user profile)
- Click Add Attribute
- Configure:
- Data type:
string - Display name:
GitHub Username - Variable name:
githubUsername - Description:
User's GitHub username for team sync
- Data type:
- Click Save
Then set APP_OKTA_GITHUB_USER_FIELD=githubUsername.
Ensure your Okta groups follow a naming convention that can be matched by sync rules:
Example naming conventions:
| Pattern | Example Groups |
|---|---|
github-{team} |
github-engineering, github-platform |
gh-eng-{team} |
gh-eng-frontend, gh-eng-backend |
Team - {name} |
Team - Platform, Team - Security |
Groups can be:
- Okta groups (manually managed)
- Groups synced from Active Directory
- Groups from other identity providers
# Required Okta configuration
APP_OKTA_DOMAIN=your-org.okta.com
APP_OKTA_CLIENT_ID=0oa1abc2def3ghi4j5k6
APP_OKTA_GITHUB_USER_FIELD=githubUsername
# Private key (choose one method)
APP_OKTA_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----"
# Or use a file path
APP_OKTA_PRIVATE_KEY_PATH=/path/to/okta-private-key.pem
# Or use AWS SSM parameter
APP_OKTA_PRIVATE_KEY=arn:aws:ssm:us-east-1:123456789:parameter/github-bot/okta-keyDefine how Okta groups map to GitHub teams:
APP_OKTA_SYNC_RULES='[
{
"name": "engineering-teams",
"enabled": true,
"okta_group_pattern": "^github-eng-.*",
"github_team_prefix": "eng-",
"strip_prefix": "github-eng-",
"sync_members": true,
"create_team_if_missing": true
}
]'See the main README for complete sync rule documentation.
Test your Okta configuration:
# Test OAuth token retrieval (manual verification)
# The app will automatically authenticate on startup
# Check app logs for:
# - "okta client initialized"
# - No authentication errors during syncTrigger a sync and verify:
- POST to
/scheduled/okta-syncendpoint - Check logs for groups discovered and teams synced
- Verify GitHub team memberships match Okta groups
- Verify
APP_OKTA_CLIENT_IDmatches the Client ID in Okta - Check the private key is the one generated for this specific app
- Ensure the key format is correct (PEM with proper headers)
- Verify
okta.groups.readscope is granted - Check your sync rule patterns match actual group names
- Test the regex pattern against your group names
- Verify
okta.users.readscope is granted - Check
APP_OKTA_GITHUB_USER_FIELDpoints to a valid profile field - Ensure users have the GitHub username field populated
- Only
ACTIVEusers are synced - suspended users are skipped
Okta has API rate limits. If you hit limits:
- Reduce sync frequency
- The app handles rate limit responses gracefully
- API Services apps need explicit scope grants
- Check that scopes were granted (not just requested)
- Super Admin role may be required to grant certain scopes