Skip to content

Commit 7bdc98d

Browse files
authored
feat: add Okta authentication support (#5195)
1 parent 6520980 commit 7bdc98d

File tree

11 files changed

+568
-10
lines changed

11 files changed

+568
-10
lines changed

docs/authentication/okta.md

Lines changed: 282 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
# Okta Integration Guide
2+
3+
This document provides comprehensive information about the Okta integration in Keep, including configuration, deployment, maintenance, and testing.
4+
5+
## Overview
6+
7+
Keep supports Okta as an authentication provider, enabling:
8+
- Single Sign-On (SSO) via Okta
9+
- JWT token validation with JWKS
10+
- User and group management through Okta
11+
- Role-based access control
12+
- Token refresh capabilities
13+
14+
## Environment Variables
15+
16+
### Backend Environment Variables
17+
18+
| Variable | Description | Example |
19+
|----------|-------------|---------|
20+
| `AUTH_TYPE` | Set to `"okta"` to enable Okta authentication | `okta` |
21+
| `OKTA_DOMAIN` | Your Okta domain | `company.okta.com` |
22+
| `OKTA_API_TOKEN` | Admin API token for Okta management | `00aBcD3f4GhIJkl5m6NoPQr` |
23+
| `OKTA_ISSUER` | The issuer URL for your Okta application | `https://company.okta.com/oauth2/default` |
24+
| `OKTA_CLIENT_ID` | Client ID of your Okta application | `0oa1b2c3d4e5f6g7h8i9j` |
25+
| `OKTA_CLIENT_SECRET` | Client Secret of your Okta application | `abcd1234efgh5678ijkl9012` |
26+
| `OKTA_AUDIENCE` | (Optional) The audience for token validation | `api://keep` |
27+
28+
### Frontend Environment Variables
29+
30+
| Variable | Description | Example |
31+
|----------|-------------|---------|
32+
| `AUTH_TYPE` | Set to `"OKTA"` to enable Okta authentication | `OKTA` |
33+
| `OKTA_CLIENT_ID` | Client ID of your Okta application | `0oa1b2c3d4e5f6g7h8i9j` |
34+
| `OKTA_CLIENT_SECRET` | Client Secret of your Okta application | `abcd1234efgh5678ijkl9012` |
35+
| `OKTA_ISSUER` | The issuer URL for your Okta application | `https://company.okta.com/oauth2/default` |
36+
| `OKTA_DOMAIN` | Your Okta domain | `company.okta.com` |
37+
38+
## Okta Configuration
39+
40+
### Creating an Okta Application
41+
42+
1. Sign in to your Okta Admin Console
43+
2. Navigate to **Applications** > **Applications**
44+
3. Click **Create App Integration**
45+
4. Select **OIDC - OpenID Connect** as the Sign-in method
46+
5. Choose **Web Application** as the Application type
47+
6. Click **Next**
48+
49+
### Application Settings
50+
51+
1. **Name**: Enter a name for your application (e.g., "Keep")
52+
2. **Grant type**: Select Authorization Code
53+
3. **Sign-in redirect URIs**: Enter your app's callback URL, e.g., `https://your-keep-domain.com/api/auth/callback/okta`
54+
4. **Sign-out redirect URIs**: Enter your app's sign-out URL, e.g., `https://your-keep-domain.com/signin`
55+
5. **Assignments**:
56+
- **Skip group assignment for now** or assign to appropriate groups
57+
6. Click **Save**
58+
59+
### Create API Token
60+
61+
1. Navigate to **Security** > **API**
62+
2. Select the **Tokens** tab
63+
3. Click **Create Token**
64+
4. Name your token (e.g., "Keep Integration")
65+
5. Copy the generated token value (this will be your `OKTA_API_TOKEN`)
66+
67+
### Configure OIDC Claims (Optional but Recommended)
68+
69+
1. Navigate to your application
70+
2. Go to the **Sign On** tab
71+
3. Under **OpenID Connect ID Token**, click **Edit**
72+
4. Add custom claims:
73+
- `keep_tenant_id`: The tenant ID in Keep
74+
- `keep_role`: The user's role in Keep
75+
76+
## Deployment Instructions
77+
78+
### Docker Deployment
79+
80+
Add the required environment variables to your docker-compose file or Kubernetes deployment:
81+
82+
```yaml
83+
environment:
84+
- AUTH_TYPE=okta
85+
- OKTA_DOMAIN=your-company.okta.com
86+
- OKTA_API_TOKEN=your-api-token
87+
- OKTA_ISSUER=https://your-company.okta.com/oauth2/default
88+
- OKTA_CLIENT_ID=your-client-id
89+
- OKTA_CLIENT_SECRET=your-client-secret
90+
```
91+
92+
### Next.js Frontend
93+
94+
Configure environment variables in your `.env.local` file:
95+
96+
```
97+
AUTH_TYPE=OKTA
98+
OKTA_CLIENT_ID=your-client-id
99+
OKTA_CLIENT_SECRET=your-client-secret
100+
OKTA_ISSUER=https://your-company.okta.com/oauth2/default
101+
OKTA_DOMAIN=your-company.okta.com
102+
```
103+
104+
### Vercel Deployment
105+
106+
Add the environment variables in your Vercel project settings.
107+
108+
## User and Group Management
109+
110+
### Users
111+
112+
The system automatically maps Okta users to Keep users. Key mappings:
113+
114+
- Okta email → Keep email
115+
- Okta firstName → Keep name
116+
- Okta groups → Keep groups
117+
- Custom claim `keep_role` → Keep role (defaults to "user" if not specified)
118+
119+
### Groups
120+
121+
Groups in Okta are synchronized with Keep. Groups with names starting with `keep_` are treated as roles.
122+
123+
### Roles
124+
125+
Roles are implemented as Okta groups with the prefix `keep_`. For example:
126+
- `keep_admin` → Admin role in Keep
127+
- `keep_user` → User role in Keep
128+
129+
## Authentication Flow
130+
131+
1. User accesses Keep application
132+
2. User is redirected to Okta login page
133+
3. After successful authentication, Okta returns an ID token and access token
134+
4. Keep validates the token using Okta's JWKS endpoint
135+
5. Keep extracts user information and permissions from the token
136+
6. When tokens expire, Keep automatically refreshes them using the refresh token
137+
138+
## Token Refresh
139+
140+
The refresh token flow is handled automatically by the application:
141+
142+
1. The system detects when an access token is about to expire
143+
2. It uses the refresh token to obtain a new access token from Okta
144+
3. The new token is stored and used for subsequent requests
145+
146+
## Testing Strategies
147+
148+
### Unit Tests
149+
150+
1. **AuthVerifier Tests**: Test token validation with mock tokens
151+
```python
152+
def test_okta_verify_bearer_token():
153+
# Create a mock token with the expected claims
154+
# Initialize the OktaAuthVerifier
155+
# Verify the token is validated correctly
156+
```
157+
158+
2. **IdentityManager Tests**: Test user and group management
159+
```python
160+
def test_okta_create_user():
161+
# Mock Okta API responses
162+
# Test creating a user
163+
# Verify the correct API calls are made
164+
```
165+
166+
### Integration Tests
167+
168+
1. **End-to-End Authentication Flow**:
169+
- Create a test user in Okta
170+
- Attempt to log in to the application
171+
- Verify successful authentication
172+
173+
2. **Token Refresh Test**:
174+
- Obtain an access token and refresh token
175+
- Wait for token expiration
176+
- Verify token refresh occurs automatically
177+
178+
3. **Role-Based Access Control**:
179+
- Create users with different roles
180+
- Verify access to different endpoints based on roles
181+
182+
### Load Tests
183+
184+
1. **Token Validation Performance**:
185+
- Simulate multiple concurrent requests with tokens
186+
- Measure response time and system load
187+
- Verify JWKS caching is working correctly
188+
189+
2. **User Management Scaling**:
190+
- Test with a large number of users and groups
191+
- Measure performance of group and user operations
192+
193+
## Troubleshooting
194+
195+
### Common Issues
196+
197+
1. **Invalid Token Errors**:
198+
- Check that `OKTA_ISSUER` matches the issuer in your Okta application
199+
- Verify that token signing algorithm (RS256) is supported
200+
- Check for clock skew between your server and Okta
201+
202+
2. **API Request Failures**:
203+
- Verify that `OKTA_API_TOKEN` is valid and has sufficient permissions
204+
- Check rate limiting on Okta API
205+
206+
3. **User Not Found**:
207+
- Verify that the user exists in Okta
208+
- Check user status (active/deactivated)
209+
210+
### Debugging
211+
212+
1. Enable debug logging:
213+
```
214+
AUTH_DEBUG=true
215+
```
216+
217+
2. Check Okta API logs in the Okta Admin Console
218+
219+
## Maintenance Considerations
220+
221+
### Token Rotation
222+
223+
- Rotate the `OKTA_API_TOKEN` periodically for security
224+
- Update the application with the new token without downtime
225+
226+
### JWKS Caching
227+
228+
- The implementation caches JWKS keys for 24 hours
229+
- Adjust the cache duration if needed based on key rotation policy
230+
231+
### Custom Claims
232+
233+
- When adding new custom claims, update both Okta configuration and code
234+
235+
### API Rate Limits
236+
237+
- Be aware of Okta API rate limits
238+
- Implement retry logic for rate limit errors
239+
240+
## Code Structure
241+
242+
### Backend Components
243+
244+
- **`keep/identitymanager/identity_managers/okta/okta_authverifier.py`**: Handles JWT validation with JWKS
245+
- **`keep/identitymanager/identity_managers/okta/okta_identitymanager.py`**: Manages users, groups, and roles via Okta API
246+
247+
### Frontend Components
248+
249+
- **`auth.config.ts`**: NextAuth.js configuration for Okta
250+
- **`authenticationType.ts`**: Defines Okta as an authentication type
251+
252+
## Security Considerations
253+
254+
1. **Secure Storage of Secrets**:
255+
- Store `OKTA_CLIENT_SECRET` and `OKTA_API_TOKEN` securely
256+
- Never commit secrets to version control
257+
258+
2. **Token Validation**:
259+
- Always validate tokens with proper signature verification
260+
- Verify token audience and issuer
261+
262+
3. **Scoped API Tokens**:
263+
- Use the principle of least privilege for API tokens
264+
265+
## Future Improvements
266+
267+
1. **Enhanced Group Mapping**:
268+
- Implement more sophisticated group-to-role mappings
269+
- Support nested groups in Okta
270+
271+
2. **Custom Authorization Servers**:
272+
- Support multiple Okta authorization servers
273+
- Allow tenant-specific authorization servers
274+
275+
3. **Custom Scope Handling**:
276+
- Better integrate Okta scopes with Keep permissions
277+
278+
## Support and Resources
279+
280+
- [Okta Developer Documentation](https://developer.okta.com/docs/reference/)
281+
- [NextAuth.js Okta Provider Documentation](https://next-auth.js.org/providers/okta)
282+
- [JWT Debugging Tools](https://jwt.io/)

docs/deployment/authentication/overview.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Keep supports various authentication providers and architectures to accommodate
1414
- [**Auth0**](/deployment/authentication/auth0-auth) - Utilize Auth0 for scalable, auth0-based authentication.
1515
- [**Keycloak**](/deployment/authentication/keycloak-auth) - Utilize Keycloak for enterprise authentication methods such as SSO/SAML/OIDC, advanced RBAC with custom roles, resource-level permissions, and integration with user directories (LDAP).
1616
- [**AzureAD**](/deployment/authentication/azuread-auth) - Utilize Azure AD for SSO/SAML/OIDC nterprise authentication.
17+
- [**Okta**](/deployment/authentication/okta-auth) - Utilize Okta for SSO/OIDC authentication.
1718

1819
Choosing the right authentication strategy depends on your specific use case, security requirements, and deployment environment. You can read more about each authentication provider.
1920

@@ -29,6 +30,7 @@ Choosing the right authentication strategy depends on your specific use case, se
2930
| **Keycloak** | ✅ <br />(Custom roles) ||||||| **EE** |
3031
| **Oauth2Proxy** | ✅ <br />(Predefiend roles) |||| N/A | N/A || **OSS** |
3132
| **Azure AD** | ✅ <br />(Predefiend roles) |||| By Azure AD | By Azure AD || **EE** |
33+
| **Okta** | ✅ <br />(Predefiend roles) ||||||| **OSS** |
3234
### How To Configure
3335
<Tip>
3436
Some authentication providers require additional environment variables. These will be covered in detail on the specific authentication provider pages.
@@ -44,5 +46,6 @@ The authentication scheme on Keep is controlled with environment variables both
4446
| **Keycloak** | `AUTH_TYPE=KEYCLOAK` | `KEYCLOAK_URL`, `KEYCLOAK_REALM`, `KEYCLOAK_CLIENT_ID`, `KEYCLOAK_CLIENT_SECRET` |
4547
| **Oauth2Proxy** | `AUTH_TYPE=OAUTH2PROXY` | `OAUTH2_PROXY_USER_HEADER`, `OAUTH2_PROXY_ROLE_HEADER`, `OAUTH2_PROXY_AUTO_CREATE_USER` |
4648
| **AzureAD** | `AUTH_TYPE=AZUREAD` | See [AzureAD Configuration](/deployment/authentication/azuread-auth) |
49+
| **Okta** | `AUTH_TYPE=OKTA` | `OKTA_DOMAIN`, `OKTA_CLIENT_ID`, `OKTA_CLIENT_SECRET` |
4750

4851
For more details on each authentication strategy, including setup instructions and implications, refer to the respective sections.

docs/deployment/configuration.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ Keep is highly configurable through environment variables. This allows you to cu
9494

9595
| Env var | Purpose | Required | Default Value | Valid options |
9696
| :-----------------------------------: | :---------------------------------------------------------------: | :------: | :-----------: | :------------------------------------------------: |
97-
| **AUTH_TYPE** | Specifies the authentication type | No | "NOAUTH" | "AUTH0", "KEYCLOAK", "DB", "NOAUTH", "OAUTH2PROXY" |
97+
| **AUTH_TYPE** | Specifies the authentication type | No | "NOAUTH" | "AUTH0", "KEYCLOAK", "DB", "NOAUTH", "OAUTH2PROXY", "OKTA" |
9898
| **KEEP_JWT_SECRET** | Secret key for JWT token generation and validation (DB auth only) | Yes | None | Any strong secret string |
9999
| **KEEP_DEFAULT_USERNAME** | Default username for the admin user (DB auth only) | No | "keep" | Any valid username string |
100100
| **KEEP_DEFAULT_PASSWORD** | Default password for the admin user (DB auth only) | No | "keep" | Any strong password string |
@@ -331,7 +331,7 @@ These endpoints are rate-limited according to the `KEEP_LIMIT_CONCURRENCY` setti
331331

332332
| Env var | Purpose | Required | Default Value | Valid options |
333333
| :-----------------: | :-------------------------------: | :------: | :-----------: | :------------------------------------------------: |
334-
| **AUTH_TYPE** | Specifies the authentication type | No | "noauth" | "auth0", "keycloak", "db", "noauth", "oauth2proxy" |
334+
| **AUTH_TYPE** | Specifies the authentication type | No | "noauth" | "auth0", "keycloak", "db", "noauth", "oauth2proxy", "okta" |
335335
| **NEXTAUTH_URL** | URL for NextAuth authentication | Yes | None | Valid URL |
336336
| **NEXTAUTH_SECRET** | Secret key for NextAuth | Yes | None | Strong secret string |
337337

keep-ui/app/(signin)/error/authEnvUtils.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ export function getAuthTypeEnvVars(authType: string | undefined): AuthEnvVars {
3030
KEYCLOAK_SECRET: maskValue(process.env.KEYCLOAK_SECRET),
3131
KEYCLOAK_ISSUER: maskValue(process.env.KEYCLOAK_ISSUER),
3232
};
33+
case AuthType.OKTA:
34+
return {
35+
OKTA_CLIENT_ID: maskValue(process.env.OKTA_CLIENT_ID),
36+
OKTA_CLIENT_SECRET: maskValue(process.env.OKTA_CLIENT_SECRET),
37+
OKTA_ISSUER: maskValue(process.env.OKTA_ISSUER),
38+
OKTA_DOMAIN: maskValue(process.env.OKTA_DOMAIN),
39+
};
3340
case AuthType.DB:
3441
return {
3542
API_URL: maskValue(process.env.API_URL),

keep-ui/app/(signin)/signin/SignInForm.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export interface Providers {
2121
credentials?: Provider;
2222
keycloak?: Provider;
2323
"microsoft-entra-id"?: Provider;
24+
okta?: Provider;
2425
}
2526

2627
interface SignInFormInputs {
@@ -74,6 +75,9 @@ export default function SignInForm({
7475
} else if (providers.keycloak) {
7576
console.log("Signing in with keycloak provider");
7677
signIn("keycloak", { callbackUrl: "/" });
78+
} else if (providers.okta) {
79+
console.log("Signing in with Okta provider");
80+
signIn("okta", { callbackUrl: "/" });
7781
} else if (providers["microsoft-entra-id"]) {
7882
console.log("Signing in with Azure AD provider");
7983
signIn("microsoft-entra-id", { callbackUrl: "/" });

0 commit comments

Comments
 (0)