okta-auth-cli 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. okta_auth_cli-0.1.1/.github/CODEOWNERS +1 -0
  2. okta_auth_cli-0.1.1/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
  3. okta_auth_cli-0.1.1/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. okta_auth_cli-0.1.1/.github/ISSUE_TEMPLATE/feature_request.md +13 -0
  5. okta_auth_cli-0.1.1/.github/dependabot.yml +12 -0
  6. okta_auth_cli-0.1.1/.github/pull_request_template.md +14 -0
  7. okta_auth_cli-0.1.1/.github/workflows/ci.yml +55 -0
  8. okta_auth_cli-0.1.1/.github/workflows/dependency-review.yml +15 -0
  9. okta_auth_cli-0.1.1/.github/workflows/release.yml +50 -0
  10. okta_auth_cli-0.1.1/.gitignore +22 -0
  11. okta_auth_cli-0.1.1/.pre-commit-config.yaml +7 -0
  12. okta_auth_cli-0.1.1/AGENTS.md +61 -0
  13. okta_auth_cli-0.1.1/CLAUDE.md +61 -0
  14. okta_auth_cli-0.1.1/CONTRIBUTING.md +23 -0
  15. okta_auth_cli-0.1.1/LICENSE +21 -0
  16. okta_auth_cli-0.1.1/PKG-INFO +264 -0
  17. okta_auth_cli-0.1.1/README.md +234 -0
  18. okta_auth_cli-0.1.1/SECURITY.md +19 -0
  19. okta_auth_cli-0.1.1/pyproject.toml +76 -0
  20. okta_auth_cli-0.1.1/src/okta_auth/__init__.py +1 -0
  21. okta_auth_cli-0.1.1/src/okta_auth/auth/__init__.py +0 -0
  22. okta_auth_cli-0.1.1/src/okta_auth/auth/login.py +352 -0
  23. okta_auth_cli-0.1.1/src/okta_auth/auth/session_store.py +132 -0
  24. okta_auth_cli-0.1.1/src/okta_auth/auth/totp.py +8 -0
  25. okta_auth_cli-0.1.1/src/okta_auth/browser/__init__.py +0 -0
  26. okta_auth_cli-0.1.1/src/okta_auth/browser/controller.py +126 -0
  27. okta_auth_cli-0.1.1/src/okta_auth/browser/detection.py +140 -0
  28. okta_auth_cli-0.1.1/src/okta_auth/browser/helpers.py +50 -0
  29. okta_auth_cli-0.1.1/src/okta_auth/cli.py +261 -0
  30. okta_auth_cli-0.1.1/src/okta_auth/log.py +18 -0
  31. okta_auth_cli-0.1.1/src/okta_auth/server.py +240 -0
  32. okta_auth_cli-0.1.1/tests/test_cli.py +86 -0
  33. okta_auth_cli-0.1.1/tests/test_packaging.py +17 -0
  34. okta_auth_cli-0.1.1/tests/test_server_smoke.py +14 -0
  35. okta_auth_cli-0.1.1/tests/test_session_store.py +70 -0
  36. okta_auth_cli-0.1.1/uv.lock +1085 -0
@@ -0,0 +1 @@
1
+ * @bunizao
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: Bug report
3
+ about: Report an issue in okta-auth-mcp
4
+ labels: bug
5
+ ---
6
+
7
+ ## Description
8
+
9
+ ## Steps to Reproduce
10
+
11
+ 1.
12
+ 2.
13
+ 3.
14
+
15
+ ## Expected Behavior
16
+
17
+ ## Actual Behavior
18
+
19
+ ## Environment
20
+
21
+ - OS:
22
+ - Python version:
23
+ - Package version:
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security report
4
+ url: https://github.com/bunizao/okta-auth-mcp/security/advisories/new
5
+ about: Please report security issues privately.
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: Feature request
3
+ about: Propose an enhancement
4
+ labels: enhancement
5
+ ---
6
+
7
+ ## Problem
8
+
9
+ ## Proposed Solution
10
+
11
+ ## Alternatives Considered
12
+
13
+ ## Additional Context
@@ -0,0 +1,12 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ open-pull-requests-limit: 5
8
+ - package-ecosystem: "github-actions"
9
+ directory: "/"
10
+ schedule:
11
+ interval: "weekly"
12
+ open-pull-requests-limit: 5
@@ -0,0 +1,14 @@
1
+ ## Summary
2
+
3
+ -
4
+
5
+ ## Validation
6
+
7
+ - [ ] `ruff format --check .`
8
+ - [ ] `ruff check .`
9
+ - [ ] `pytest`
10
+
11
+ ## Security
12
+
13
+ - [ ] No secrets/session artifacts were added to the repo
14
+ - [ ] Changes to auth/session paths considered threat model
@@ -0,0 +1,55 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main, master]
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ lint:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v6
17
+
18
+ - name: Setup Python
19
+ uses: actions/setup-python@v6
20
+ with:
21
+ python-version: "3.12"
22
+
23
+ - name: Install dependencies
24
+ run: |
25
+ python -m pip install -U pip
26
+ pip install -e .[dev]
27
+
28
+ - name: Ruff format check
29
+ run: ruff format --check .
30
+
31
+ - name: Ruff lint
32
+ run: ruff check .
33
+
34
+ test:
35
+ runs-on: ubuntu-latest
36
+ strategy:
37
+ fail-fast: false
38
+ matrix:
39
+ python-version: ["3.11", "3.12", "3.13"]
40
+ steps:
41
+ - name: Checkout
42
+ uses: actions/checkout@v6
43
+
44
+ - name: Setup Python
45
+ uses: actions/setup-python@v6
46
+ with:
47
+ python-version: ${{ matrix.python-version }}
48
+
49
+ - name: Install dependencies
50
+ run: |
51
+ python -m pip install -U pip
52
+ pip install -e .[dev]
53
+
54
+ - name: Run tests
55
+ run: pytest
@@ -0,0 +1,15 @@
1
+ name: Dependency Review
2
+
3
+ on:
4
+ pull_request:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ jobs:
10
+ dependency-review:
11
+ if: ${{ !github.event.repository.private }}
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: Dependency review
15
+ uses: actions/dependency-review-action@v4
@@ -0,0 +1,50 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - name: Checkout
16
+ uses: actions/checkout@v6
17
+
18
+ - name: Setup Python
19
+ uses: actions/setup-python@v6
20
+ with:
21
+ python-version: "3.12"
22
+
23
+ - name: Build artifacts
24
+ run: |
25
+ python -m pip install -U pip build twine
26
+ python -m build
27
+ twine check dist/*
28
+
29
+ - name: Upload artifacts
30
+ uses: actions/upload-artifact@v7
31
+ with:
32
+ name: dist
33
+ path: dist/
34
+
35
+ publish:
36
+ needs: build
37
+ runs-on: ubuntu-latest
38
+ environment: pypi
39
+ permissions:
40
+ id-token: write
41
+ contents: read
42
+ steps:
43
+ - name: Download artifacts
44
+ uses: actions/download-artifact@v8
45
+ with:
46
+ name: dist
47
+ path: dist/
48
+
49
+ - name: Publish to PyPI
50
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,22 @@
1
+ # macOS
2
+ .DS_Store
3
+
4
+ # Python caches
5
+ __pycache__/
6
+ *.py[cod]
7
+ *$py.class
8
+
9
+ # Virtual environments
10
+ .venv/
11
+ venv/
12
+
13
+ # Tool caches
14
+ .pytest_cache/
15
+ .mypy_cache/
16
+ .ruff_cache/
17
+
18
+ # Build artifacts
19
+ build/
20
+ dist/
21
+ *.egg-info/
22
+
@@ -0,0 +1,7 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.13.2
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
@@ -0,0 +1,61 @@
1
+ # AGENTS.md
2
+
3
+ This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ okta-auth is an Okta login toolkit with an interactive CLI and an MCP server for session reuse. It uses Playwright to automate Okta SSO and persists per-domain session state for reuse by AI agents.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Setup
13
+ uv venv && source .venv/bin/activate
14
+ uv pip install -e '.[dev]'
15
+ playwright install chromium
16
+
17
+ # Quality gates (run all three before submitting)
18
+ ruff format --check .
19
+ ruff check .
20
+ pytest
21
+
22
+ # Run single test
23
+ pytest tests/test_session_store.py -v
24
+
25
+ # Run interactive CLI
26
+ okta
27
+
28
+ # Run MCP server (stdio transport, stdout is JSON-RPC)
29
+ okta-auth
30
+ ```
31
+
32
+ ## Architecture
33
+
34
+ ```
35
+ src/okta_auth/
36
+ ├── server.py # FastMCP entry point, defines all 5 MCP tools
37
+ ├── log.py # Stderr-only logging (stdout reserved for JSON-RPC)
38
+ ├── auth/
39
+ │ ├── login.py # auto_login() engine: selector-based form filling, portal detection, MFA/TOTP
40
+ │ ├── session_store.py # Per-domain session CRUD at ~/.okta-auth/sessions/
41
+ │ └── totp.py # pyotp wrapper for TOTP code generation
42
+ └── browser/
43
+ ├── controller.py # BrowserController async context manager, BrowserConfig dataclass
44
+ ├── detection.py # Cross-platform browser executable discovery with env var overrides
45
+ └── helpers.py # fill_first_match(), click_first_match(), maybe_switch_to_code_factor()
46
+ ```
47
+
48
+ ### Key Patterns
49
+
50
+ - **Selector redundancy**: `login.py` defines 16+ CSS selectors per form field (USERNAME_SELECTORS, PASSWORD_SELECTORS, etc.) tried in priority order for broad Okta form compatibility.
51
+ - **Portal detection**: `_is_on_portal()` confirms auth completion by checking domain change + login field absence.
52
+ - **Session keying**: Sessions are stored as `{domain_hash}.json` + `{domain_hash}.meta.json` using the URL's netloc as the domain key.
53
+ - **Async-first**: All I/O uses `async/await`; the server runs on asyncio via FastMCP.
54
+ - **Browser fallback**: `BrowserController` tries the requested channel first, falls back to default Chromium on launch failure.
55
+
56
+ ## Code Style
57
+
58
+ - **Formatter/Linter**: Ruff (line-length 100, target py311, double quotes, LF endings)
59
+ - **Lint rules**: E, F, I (isort), B (flake8-bugbear); E501 ignored
60
+ - **Type checking**: mypy with `check_untyped_defs = true`, `ignore_missing_imports = true`
61
+ - **All logs go to stderr** — never print to stdout (breaks MCP stdio transport)
@@ -0,0 +1,61 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ okta-auth is an Okta login toolkit with an interactive CLI and an MCP server for session reuse. It uses Playwright to automate Okta SSO and persists per-domain session state for reuse by AI agents.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Setup
13
+ uv venv && source .venv/bin/activate
14
+ uv pip install -e '.[dev]'
15
+ playwright install chromium
16
+
17
+ # Quality gates (run all three before submitting)
18
+ ruff format --check .
19
+ ruff check .
20
+ pytest
21
+
22
+ # Run single test
23
+ pytest tests/test_session_store.py -v
24
+
25
+ # Run interactive CLI
26
+ okta
27
+
28
+ # Run MCP server (stdio transport, stdout is JSON-RPC)
29
+ okta-auth
30
+ ```
31
+
32
+ ## Architecture
33
+
34
+ ```
35
+ src/okta_auth/
36
+ ├── server.py # FastMCP entry point, defines all 5 MCP tools
37
+ ├── log.py # Stderr-only logging (stdout reserved for JSON-RPC)
38
+ ├── auth/
39
+ │ ├── login.py # auto_login() engine: selector-based form filling, portal detection, MFA/TOTP
40
+ │ ├── session_store.py # Per-domain session CRUD at ~/.okta-auth/sessions/
41
+ │ └── totp.py # pyotp wrapper for TOTP code generation
42
+ └── browser/
43
+ ├── controller.py # BrowserController async context manager, BrowserConfig dataclass
44
+ ├── detection.py # Cross-platform browser executable discovery with env var overrides
45
+ └── helpers.py # fill_first_match(), click_first_match(), maybe_switch_to_code_factor()
46
+ ```
47
+
48
+ ### Key Patterns
49
+
50
+ - **Selector redundancy**: `login.py` defines 16+ CSS selectors per form field (USERNAME_SELECTORS, PASSWORD_SELECTORS, etc.) tried in priority order for broad Okta form compatibility.
51
+ - **Portal detection**: `_is_on_portal()` confirms auth completion by checking domain change + login field absence.
52
+ - **Session keying**: Sessions are stored as `{domain_hash}.json` + `{domain_hash}.meta.json` using the URL's netloc as the domain key.
53
+ - **Async-first**: All I/O uses `async/await`; the server runs on asyncio via FastMCP.
54
+ - **Browser fallback**: `BrowserController` tries the requested channel first, falls back to default Chromium on launch failure.
55
+
56
+ ## Code Style
57
+
58
+ - **Formatter/Linter**: Ruff (line-length 100, target py311, double quotes, LF endings)
59
+ - **Lint rules**: E, F, I (isort), B (flake8-bugbear); E501 ignored
60
+ - **Type checking**: mypy with `check_untyped_defs = true`, `ignore_missing_imports = true`
61
+ - **All logs go to stderr** — never print to stdout (breaks MCP stdio transport)
@@ -0,0 +1,23 @@
1
+ # Contributing
2
+
3
+ ## Setup
4
+
5
+ ```bash
6
+ uv venv && source .venv/bin/activate
7
+ uv pip install -e '.[dev]'
8
+ playwright install chromium
9
+ ```
10
+
11
+ ## Local Quality Gates
12
+
13
+ ```bash
14
+ ruff format --check .
15
+ ruff check .
16
+ pytest
17
+ ```
18
+
19
+ ## Pull Requests
20
+
21
+ - Keep PRs focused and small.
22
+ - Add/update tests for behavior changes.
23
+ - Do not commit secrets, cookies, or local session files.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 bunizao
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.4
2
+ Name: okta-auth-cli
3
+ Version: 0.1.1
4
+ Summary: Okta login toolkit with an interactive CLI and MCP session reuse
5
+ Project-URL: Homepage, https://github.com/bunizao/okta-auth
6
+ Project-URL: Issues, https://github.com/bunizao/okta-auth/issues
7
+ Author: bunizao
8
+ License: MIT
9
+ License-File: LICENSE
10
+ Keywords: authentication,mcp,okta,playwright,sso
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Python: >=3.11
20
+ Requires-Dist: mcp[cli]>=1.9.0
21
+ Requires-Dist: playwright>=1.54.0
22
+ Requires-Dist: pydantic>=2.0.0
23
+ Requires-Dist: pyotp>=2.9.0
24
+ Provides-Extra: dev
25
+ Requires-Dist: mypy>=1.11.0; extra == 'dev'
26
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
27
+ Requires-Dist: pytest>=8.2.0; extra == 'dev'
28
+ Requires-Dist: ruff>=0.6.0; extra == 'dev'
29
+ Description-Content-Type: text/markdown
30
+
31
+ # okta-auth
32
+
33
+ > **Alpha** — this project is under active development and iterating quickly.
34
+ > APIs, tool signatures, and session formats may change between releases.
35
+
36
+ Okta login toolkit with two entry points:
37
+
38
+ - `okta`: interactive CLI for humans to log in and save a session locally
39
+ - `okta-auth`: MCP server for AI agents that reuse those sessions
40
+
41
+ ## CLI Usage
42
+
43
+ Run `okta` with no arguments to start an interactive login flow:
44
+
45
+ ```bash
46
+ okta
47
+ ```
48
+
49
+ You can also pass values directly:
50
+
51
+ ```bash
52
+ okta https://portal.company.com --username you@company.com
53
+ ```
54
+
55
+ The login flow is headless by default. Pass `--headed` if you want to see the browser window.
56
+
57
+ Available commands:
58
+
59
+ - `okta [url]`: log in and save a session
60
+ - `okta check <url>`: verify a saved session
61
+ - `okta list`: list saved sessions
62
+ - `okta delete <url>`: delete a saved session
63
+ - `okta cookies <url>`: inspect stored cookies
64
+
65
+ ## MCP Tools
66
+
67
+ | Tool | Description |
68
+ |------|-------------|
69
+ | `okta_login` | Authenticate to a target URL and store session state |
70
+ | `okta_check_session` | Verify whether a stored session is still valid |
71
+ | `okta_list_sessions` | List saved sessions and metadata |
72
+ | `okta_delete_session` | Remove a stored session |
73
+ | `okta_get_cookies` | Retrieve cookies from stored session (sensitive) |
74
+
75
+ Sessions are stored under `~/.okta-auth/sessions/`. Existing sessions under
76
+ `~/.okta-auth-mcp/sessions/` are migrated automatically.
77
+
78
+ ## Security Model
79
+
80
+ - This project is intended for **local trusted execution**.
81
+ - Session files and cookies are sensitive credentials; protect the host account.
82
+ - Prefer private/internal usage unless security controls are reviewed.
83
+ - **Never pass credentials as tool arguments** — use environment variables so that AI agents never see your username, password, or TOTP secret in their context.
84
+
85
+ ## Credentials Setup
86
+
87
+ ### Environment Variables
88
+
89
+ Set credentials in your shell profile so they are inherited by the CLI or MCP server process.
90
+
91
+ ```bash
92
+ # Add to ~/.zshrc or ~/.zprofile (zsh) / ~/.bashrc (bash)
93
+ export OKTA_USERNAME="you@company.com"
94
+ export OKTA_PASSWORD="your-okta-password"
95
+ export OKTA_TOTP_SECRET="JBSWY3DPEHPK3PXP" # only if MFA is enabled
96
+ ```
97
+
98
+ After editing, reload your shell or open a new terminal, then restart the AI Agent.
99
+
100
+ The AI agent can then log in with just the URL:
101
+
102
+ ```
103
+ okta_login(url="https://portal.company.com")
104
+ ```
105
+
106
+ Explicit arguments still override environment variables if needed.
107
+
108
+ ### 1Password CLI
109
+
110
+ [`op run`](https://developer.1password.com/docs/cli/secrets-scripts/) injects secrets at process launch time. No plaintext credentials appear in shell profiles, config files, or environment variables — they live only in 1Password.
111
+
112
+ **1. Store credentials in 1Password** (one-time setup):
113
+
114
+ ```bash
115
+ op item create --category login --title "Okta MCP" \
116
+ username="you@company.com" \
117
+ password="your-okta-password" \
118
+ totp_secret="JBSWY3DPEHPK3PXP"
119
+ ```
120
+
121
+ **2. Create a secrets reference file** at `~/.okta-auth/.env` (contains paths, not values):
122
+
123
+ ```bash
124
+ OKTA_USERNAME=op://Personal/Okta MCP/username
125
+ OKTA_PASSWORD=op://Personal/Okta MCP/password
126
+ OKTA_TOTP_SECRET=op://Personal/Okta MCP/totp_secret
127
+ ```
128
+
129
+ **3. Update your MCP client config** to wrap the server with `op run`:
130
+
131
+ _Claude Code:_
132
+ ```bash
133
+ claude mcp add okta-auth -- op run --env-file=$HOME/.okta-auth/.env -- uvx --from okta-auth-cli okta-auth
134
+ ```
135
+
136
+ _Claude Desktop / Cursor / Windsurf:_
137
+ ```json
138
+ {
139
+ "mcpServers": {
140
+ "okta-auth": {
141
+ "command": "op",
142
+ "args": ["run", "--env-file=/Users/yourname/.okta-auth/.env", "--", "uvx", "--from", "okta-auth-cli", "okta-auth"]
143
+ }
144
+ }
145
+ }
146
+ ```
147
+
148
+ `op run` prompts for biometric/Touch ID once per session. Install 1Password CLI via `brew install 1password-cli`.
149
+
150
+ ### macOS Keychain
151
+
152
+ A built-in alternative that requires no extra tools. Credentials are stored in the system Keychain and fetched on each shell startup.
153
+
154
+ **Store** (one-time, run in terminal):
155
+
156
+ ```bash
157
+ security add-generic-password -a okta-mcp -s OKTA_USERNAME -w "you@company.com"
158
+ security add-generic-password -a okta-mcp -s OKTA_PASSWORD -w "your-okta-password"
159
+ security add-generic-password -a okta-mcp -s OKTA_TOTP_SECRET -w "JBSWY3DPEHPK3PXP"
160
+ ```
161
+
162
+ **Load** in `~/.zshrc` or `~/.zprofile`:
163
+
164
+ ```bash
165
+ export OKTA_USERNAME=$(security find-generic-password -a okta-mcp -s OKTA_USERNAME -w 2>/dev/null)
166
+ export OKTA_PASSWORD=$(security find-generic-password -a okta-mcp -s OKTA_PASSWORD -w 2>/dev/null)
167
+ export OKTA_TOTP_SECRET=$(security find-generic-password -a okta-mcp -s OKTA_TOTP_SECRET -w 2>/dev/null)
168
+ ```
169
+
170
+ macOS may prompt for Keychain access on the first load after a reboot.
171
+
172
+ ### How to Get Your TOTP Secret Key
173
+
174
+ The TOTP secret is the Base32 key (16–32 uppercase letters and digits) that backs your authenticator app. You need to obtain it **during the initial MFA enrollment** — it cannot be retrieved from an already-configured authenticator app.
175
+
176
+ #### During Okta MFA setup
177
+
178
+ 1. In Okta, go to **Settings → Security Methods** (or follow your admin's enrollment link).
179
+ 2. Choose **Google Authenticator** as the factor type.
180
+ 3. The QR code screen also shows a **"Can't scan?"** link — click it.
181
+ 4. Copy the displayed text key (e.g. `JBSWY3DPEHPK3PXP`). This is your `OKTA_TOTP_SECRET`.
182
+ 5. Finish enrollment by entering the 6-digit code from your authenticator app to confirm.
183
+
184
+ > This project does **not** currently support portals that use **only** the Okta Verify app for MFA.
185
+
186
+ #### Already enrolled and lost the secret?
187
+
188
+ You must **re-enroll** the authenticator factor to obtain a new secret:
189
+
190
+ 1. Go to **Okta → Settings → Security Methods**.
191
+ 2. Remove the existing authenticator entry.
192
+ 3. Re-add it and follow the steps above to capture the secret before scanning the QR code.
193
+
194
+ ## Installation
195
+
196
+ ### With uv tool
197
+
198
+ ```bash
199
+ uv tool install okta-auth-cli
200
+ okta
201
+ ```
202
+
203
+ ### With pipx
204
+
205
+ ```bash
206
+ pipx install okta-auth-cli
207
+ okta
208
+ ```
209
+
210
+ ### With pip
211
+
212
+ ```bash
213
+ pip install okta-auth-cli
214
+ okta
215
+ ```
216
+
217
+ ### Browser setup
218
+
219
+ The server uses Playwright for browser automation. It **automatically detects and prefers your system Chrome/Edge** — no extra download required if you already have one installed.
220
+
221
+ If no system browser is found, install the Playwright-bundled Chromium as fallback:
222
+
223
+ ```bash
224
+ playwright install chromium
225
+ ```
226
+
227
+ ## MCP Client Configuration
228
+
229
+ ### Claude Code
230
+
231
+ ```bash
232
+ claude mcp add okta-auth -- uvx --from okta-auth-cli okta-auth
233
+ ```
234
+
235
+ ### Claude Desktop / Cursor / Windsurf
236
+
237
+ ```json
238
+ {
239
+ "mcpServers": {
240
+ "okta-auth": {
241
+ "command": "uvx",
242
+ "args": ["--from", "okta-auth-cli", "okta-auth"]
243
+ }
244
+ }
245
+ }
246
+ ```
247
+
248
+ Use `okta` for the interactive CLI. Use `okta-auth` only when wiring the package into an MCP client.
249
+
250
+ ## Development
251
+
252
+ ```bash
253
+ uv venv && source .venv/bin/activate
254
+ uv pip install -e '.[dev]'
255
+ playwright install chromium
256
+ ```
257
+
258
+ Run checks locally:
259
+
260
+ ```bash
261
+ ruff format --check .
262
+ ruff check .
263
+ pytest
264
+ ```