signet-auth 1.0.0-beta.0
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.
- package/LICENSE +21 -0
- package/README.md +393 -0
- package/bin/sig.js +65 -0
- package/dist/auth-manager.d.ts +90 -0
- package/dist/auth-manager.js +262 -0
- package/dist/browser/adapters/playwright.adapter.d.ts +14 -0
- package/dist/browser/adapters/playwright.adapter.js +188 -0
- package/dist/browser/flows/form-login.flow.d.ts +6 -0
- package/dist/browser/flows/form-login.flow.js +35 -0
- package/dist/browser/flows/header-capture.d.ts +23 -0
- package/dist/browser/flows/header-capture.js +104 -0
- package/dist/browser/flows/hybrid-flow.d.ts +37 -0
- package/dist/browser/flows/hybrid-flow.js +104 -0
- package/dist/browser/flows/oauth-consent.flow.d.ts +20 -0
- package/dist/browser/flows/oauth-consent.flow.js +170 -0
- package/dist/cli/commands/doctor.d.ts +6 -0
- package/dist/cli/commands/doctor.js +263 -0
- package/dist/cli/commands/get.d.ts +2 -0
- package/dist/cli/commands/get.js +83 -0
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.js +244 -0
- package/dist/cli/commands/login.d.ts +2 -0
- package/dist/cli/commands/login.js +77 -0
- package/dist/cli/commands/logout.d.ts +2 -0
- package/dist/cli/commands/logout.js +11 -0
- package/dist/cli/commands/providers.d.ts +2 -0
- package/dist/cli/commands/providers.js +30 -0
- package/dist/cli/commands/remote.d.ts +1 -0
- package/dist/cli/commands/remote.js +67 -0
- package/dist/cli/commands/request.d.ts +2 -0
- package/dist/cli/commands/request.js +82 -0
- package/dist/cli/commands/status.d.ts +2 -0
- package/dist/cli/commands/status.js +41 -0
- package/dist/cli/commands/sync.d.ts +2 -0
- package/dist/cli/commands/sync.js +62 -0
- package/dist/cli/formatters.d.ts +3 -0
- package/dist/cli/formatters.js +25 -0
- package/dist/cli/main.d.ts +8 -0
- package/dist/cli/main.js +125 -0
- package/dist/config/generator.d.ts +24 -0
- package/dist/config/generator.js +97 -0
- package/dist/config/loader.d.ts +21 -0
- package/dist/config/loader.js +54 -0
- package/dist/config/schema.d.ts +44 -0
- package/dist/config/schema.js +8 -0
- package/dist/config/validator.d.ts +15 -0
- package/dist/config/validator.js +228 -0
- package/dist/core/errors.d.ts +57 -0
- package/dist/core/errors.js +107 -0
- package/dist/core/interfaces/auth-strategy.d.ts +48 -0
- package/dist/core/interfaces/auth-strategy.js +1 -0
- package/dist/core/interfaces/browser-adapter.d.ts +73 -0
- package/dist/core/interfaces/browser-adapter.js +1 -0
- package/dist/core/interfaces/provider.d.ts +15 -0
- package/dist/core/interfaces/provider.js +1 -0
- package/dist/core/interfaces/storage.d.ts +21 -0
- package/dist/core/interfaces/storage.js +1 -0
- package/dist/core/result.d.ts +21 -0
- package/dist/core/result.js +16 -0
- package/dist/core/types.d.ts +128 -0
- package/dist/core/types.js +6 -0
- package/dist/deps.d.ts +20 -0
- package/dist/deps.js +54 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +37 -0
- package/dist/providers/auto-provision.d.ts +9 -0
- package/dist/providers/auto-provision.js +27 -0
- package/dist/providers/config-loader.d.ts +7 -0
- package/dist/providers/config-loader.js +7 -0
- package/dist/providers/provider-registry.d.ts +19 -0
- package/dist/providers/provider-registry.js +68 -0
- package/dist/storage/cached-storage.d.ts +24 -0
- package/dist/storage/cached-storage.js +57 -0
- package/dist/storage/directory-storage.d.ts +25 -0
- package/dist/storage/directory-storage.js +184 -0
- package/dist/storage/memory-storage.d.ts +14 -0
- package/dist/storage/memory-storage.js +27 -0
- package/dist/strategies/api-token.strategy.d.ts +6 -0
- package/dist/strategies/api-token.strategy.js +63 -0
- package/dist/strategies/basic-auth.strategy.d.ts +6 -0
- package/dist/strategies/basic-auth.strategy.js +41 -0
- package/dist/strategies/cookie.strategy.d.ts +6 -0
- package/dist/strategies/cookie.strategy.js +118 -0
- package/dist/strategies/oauth2.strategy.d.ts +6 -0
- package/dist/strategies/oauth2.strategy.js +134 -0
- package/dist/strategies/registry.d.ts +13 -0
- package/dist/strategies/registry.js +25 -0
- package/dist/sync/remote-config.d.ts +8 -0
- package/dist/sync/remote-config.js +49 -0
- package/dist/sync/sync-engine.d.ts +10 -0
- package/dist/sync/sync-engine.js +96 -0
- package/dist/sync/transports/ssh.d.ts +18 -0
- package/dist/sync/transports/ssh.js +115 -0
- package/dist/sync/types.d.ts +17 -0
- package/dist/sync/types.js +1 -0
- package/dist/utils/duration.d.ts +9 -0
- package/dist/utils/duration.js +34 -0
- package/dist/utils/http.d.ts +4 -0
- package/dist/utils/http.js +10 -0
- package/dist/utils/jwt.d.ts +15 -0
- package/dist/utils/jwt.js +30 -0
- package/package.json +56 -0
- package/src/auth-manager.ts +331 -0
- package/src/browser/adapters/playwright.adapter.ts +247 -0
- package/src/browser/flows/form-login.flow.ts +35 -0
- package/src/browser/flows/header-capture.ts +128 -0
- package/src/browser/flows/hybrid-flow.ts +165 -0
- package/src/browser/flows/oauth-consent.flow.ts +200 -0
- package/src/cli/commands/doctor.ts +301 -0
- package/src/cli/commands/get.ts +96 -0
- package/src/cli/commands/init.ts +289 -0
- package/src/cli/commands/login.ts +94 -0
- package/src/cli/commands/logout.ts +17 -0
- package/src/cli/commands/providers.ts +39 -0
- package/src/cli/commands/remote.ts +71 -0
- package/src/cli/commands/request.ts +97 -0
- package/src/cli/commands/status.ts +48 -0
- package/src/cli/commands/sync.ts +71 -0
- package/src/cli/formatters.ts +31 -0
- package/src/cli/main.ts +144 -0
- package/src/config/generator.ts +122 -0
- package/src/config/loader.ts +70 -0
- package/src/config/schema.ts +75 -0
- package/src/config/validator.ts +281 -0
- package/src/core/errors.ts +182 -0
- package/src/core/interfaces/auth-strategy.ts +65 -0
- package/src/core/interfaces/browser-adapter.ts +81 -0
- package/src/core/interfaces/provider.ts +19 -0
- package/src/core/interfaces/storage.ts +26 -0
- package/src/core/result.ts +24 -0
- package/src/core/types.ts +194 -0
- package/src/deps.ts +80 -0
- package/src/index.ts +109 -0
- package/src/providers/auto-provision.ts +30 -0
- package/src/providers/config-loader.ts +8 -0
- package/src/providers/provider-registry.ts +79 -0
- package/src/storage/cached-storage.ts +72 -0
- package/src/storage/directory-storage.ts +204 -0
- package/src/storage/memory-storage.ts +35 -0
- package/src/strategies/api-token.strategy.ts +87 -0
- package/src/strategies/basic-auth.strategy.ts +64 -0
- package/src/strategies/cookie.strategy.ts +153 -0
- package/src/strategies/oauth2.strategy.ts +178 -0
- package/src/strategies/registry.ts +34 -0
- package/src/sync/remote-config.ts +60 -0
- package/src/sync/sync-engine.ts +113 -0
- package/src/sync/transports/ssh.ts +130 -0
- package/src/sync/types.ts +15 -0
- package/src/utils/duration.ts +34 -0
- package/src/utils/http.ts +11 -0
- package/src/utils/jwt.ts +39 -0
- package/tsconfig.json +20 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Pylon Peng
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# Signet
|
|
2
|
+
|
|
3
|
+
General-purpose authentication CLI. Manages credentials for any web service -- authenticate via browser SSO, store tokens, and make authenticated requests.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g signet-auth
|
|
9
|
+
sig init
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
That's it. `sig init` auto-detects your browser and creates `~/.signet/config.yaml` with sensible defaults.
|
|
13
|
+
|
|
14
|
+
### From source
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
git clone <repo-url> && cd signet
|
|
18
|
+
npm install
|
|
19
|
+
npm run build
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The CLI is available as `sig` (or `./bin/sig.js`).
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
sig init # Create config (interactive)
|
|
28
|
+
sig login https://jira.example.com # Authenticate via browser SSO
|
|
29
|
+
sig get jira # Get credentials for scripts/tools
|
|
30
|
+
sig request https://jira.example.com/rest/api/2/myself # Authenticated request
|
|
31
|
+
sig doctor # Check your setup
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Commands
|
|
35
|
+
|
|
36
|
+
### `init` -- Set up Signet
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
sig init # Interactive setup (detects browser, offers provider templates)
|
|
40
|
+
sig init --yes # Accept all defaults (non-interactive)
|
|
41
|
+
sig init --force # Overwrite existing config
|
|
42
|
+
sig init --channel msedge --yes # Use Edge instead of Chrome
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Creates `~/.signet/config.yaml`, `~/.signet/credentials/`, and `~/.signet/browser-data/`. Detects your installed browser and generates a commented config file.
|
|
46
|
+
|
|
47
|
+
### `doctor` -- Check your setup
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
sig doctor
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Validates your environment: config file, directories, browser availability, Node.js version, stored credentials.
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
✓ Config file exists (~/.signet/config.yaml)
|
|
57
|
+
✓ Config is valid
|
|
58
|
+
✓ Credentials directory exists (~/.signet/credentials)
|
|
59
|
+
✓ Browser data directory exists (~/.signet/browser-data)
|
|
60
|
+
✓ Browser available (chrome)
|
|
61
|
+
✓ Node.js version (v22.16.0)
|
|
62
|
+
✓ Stored credentials (2 stored credentials)
|
|
63
|
+
|
|
64
|
+
All checks passed.
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### `login` -- Authenticate with a service
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
sig login <url>
|
|
71
|
+
sig login <url> --token <value>
|
|
72
|
+
sig login <url> --username <user> --password <pass>
|
|
73
|
+
sig login <url> --strategy <cookie|oauth2|api-token|basic>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Opens a browser for SSO login by default. Use `--token` to store an API key or `--username`/`--password` for basic auth without a browser.
|
|
77
|
+
|
|
78
|
+
### `get` -- Retrieve credentials
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
sig get <provider|url>
|
|
82
|
+
sig get <provider|url> --format json|header|value
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Returns stored credentials as JSON (default), raw headers, or just the value.
|
|
86
|
+
|
|
87
|
+
### `request` -- Make authenticated HTTP requests
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
sig request <url>
|
|
91
|
+
sig request <url> --method POST --body '{"key":"value"}'
|
|
92
|
+
sig request <url> --header "X-Custom: value" --format body
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Injects credentials automatically. Supports `GET`, `POST`, `PUT`, `PATCH`. Output as full JSON response (default), body only, or headers only.
|
|
96
|
+
|
|
97
|
+
### `status` -- Check authentication status
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
sig status
|
|
101
|
+
sig status <provider>
|
|
102
|
+
sig status --format json|table
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Shows which providers are authenticated, credential types, and expiry.
|
|
106
|
+
|
|
107
|
+
### `logout` -- Clear credentials
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
sig logout [provider]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Clears credentials for a specific provider, or all providers if none specified.
|
|
114
|
+
|
|
115
|
+
### `providers` -- List configured providers
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
sig providers
|
|
119
|
+
sig providers --format json|table
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `remote` -- Manage remote credential stores
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
sig remote add <name> <host> [--user <user>] [--path <path>] [--ssh-key <key>]
|
|
126
|
+
sig remote remove <name>
|
|
127
|
+
sig remote list
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Configure SSH remotes for credential synchronization.
|
|
131
|
+
|
|
132
|
+
### `sync` -- Sync credentials with remotes
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
sig sync push [remote] [--provider <id>] [--force]
|
|
136
|
+
sig sync pull [remote] [--provider <id>] [--force]
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Push or pull credentials to/from remote machines over SSH. Use `--force` to overwrite on conflict.
|
|
140
|
+
|
|
141
|
+
## Configuration
|
|
142
|
+
|
|
143
|
+
All configuration lives in a single file: `~/.signet/config.yaml`. No env vars, no cascading, no project-local overrides.
|
|
144
|
+
|
|
145
|
+
Run `sig init` to generate a config interactively, or copy `config/config.example.yaml` to `~/.signet/config.yaml`.
|
|
146
|
+
|
|
147
|
+
### `browser` (required)
|
|
148
|
+
|
|
149
|
+
Controls the browser used for SSO authentication.
|
|
150
|
+
|
|
151
|
+
| Field | Required | Default | Description |
|
|
152
|
+
|-------|----------|---------|-------------|
|
|
153
|
+
| `browserDataDir` | **yes** | -- | Directory for persistent browser profile (cookies, localStorage). Example: `~/.signet/browser-data` |
|
|
154
|
+
| `channel` | **yes** | -- | Browser channel. Values: `chrome`, `msedge`, `chromium` |
|
|
155
|
+
| `headlessTimeout` | **yes** | -- | Timeout in ms for headless auth attempt. Headless is tried first; if it times out, falls back to visible mode. Recommended: `15000`-`30000` |
|
|
156
|
+
| `visibleTimeout` | **yes** | -- | Timeout in ms for visible (user-assisted) auth. Must be long enough for the user to complete SSO manually. Recommended: `60000`-`120000` |
|
|
157
|
+
| `waitUntil` | **yes** | -- | Page load condition before checking auth status. Values: `load` (DOM loaded), `networkidle` (no network activity for 500ms), `domcontentloaded` (HTML parsed), `commit` (first byte received) |
|
|
158
|
+
|
|
159
|
+
```yaml
|
|
160
|
+
browser:
|
|
161
|
+
browserDataDir: ~/.signet/browser-data
|
|
162
|
+
channel: chrome
|
|
163
|
+
headlessTimeout: 15000
|
|
164
|
+
visibleTimeout: 60000
|
|
165
|
+
waitUntil: load
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### `storage` (required)
|
|
169
|
+
|
|
170
|
+
Where credentials are stored on disk.
|
|
171
|
+
|
|
172
|
+
| Field | Required | Description |
|
|
173
|
+
|-------|----------|-------------|
|
|
174
|
+
| `credentialsDir` | **yes** | Directory for per-provider credential JSON files. Example: `~/.signet/credentials` |
|
|
175
|
+
|
|
176
|
+
```yaml
|
|
177
|
+
storage:
|
|
178
|
+
credentialsDir: ~/.signet/credentials
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### `remotes` (optional)
|
|
182
|
+
|
|
183
|
+
SSH remotes for syncing credentials to other machines.
|
|
184
|
+
|
|
185
|
+
| Field | Required | Description |
|
|
186
|
+
|-------|----------|-------------|
|
|
187
|
+
| `type` | **yes** | Transport type. Only `ssh` is supported |
|
|
188
|
+
| `host` | **yes** | Remote hostname or IP |
|
|
189
|
+
| `user` | no | SSH username. Defaults to current user |
|
|
190
|
+
| `path` | no | Remote credentials directory. Defaults to `~/.signet/credentials` |
|
|
191
|
+
| `sshKey` | no | Path to SSH private key. Defaults to system SSH config |
|
|
192
|
+
|
|
193
|
+
```yaml
|
|
194
|
+
remotes:
|
|
195
|
+
dev-server:
|
|
196
|
+
type: ssh
|
|
197
|
+
host: dev.example.com
|
|
198
|
+
user: deploy
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### `providers` (optional)
|
|
202
|
+
|
|
203
|
+
Provider entries map domains to authentication strategies. The key is the provider ID.
|
|
204
|
+
|
|
205
|
+
Most services work with zero config -- just run `sig login <url>` and it auto-provisions a cookie provider. Define providers explicitly for OAuth2, API tokens, or when you need custom settings.
|
|
206
|
+
|
|
207
|
+
#### Common provider fields
|
|
208
|
+
|
|
209
|
+
| Field | Required | Description |
|
|
210
|
+
|-------|----------|-------------|
|
|
211
|
+
| `domains` | **yes** | Array of domains this provider handles. Used for URL-to-provider resolution. Example: `["jira.example.com"]` |
|
|
212
|
+
| `strategy` | **yes** | Authentication strategy. Values: `cookie`, `oauth2`, `api-token`, `basic` |
|
|
213
|
+
| `name` | no | Display name. Defaults to the provider ID |
|
|
214
|
+
| `entryUrl` | no | URL to navigate to for browser-based auth. Required for `cookie` and `oauth2` strategies |
|
|
215
|
+
| `forceVisible` | no | `true` to skip headless attempt and open visible browser immediately. Use for sites requiring CAPTCHAs, QR codes, or interactive auth. Default: `false` |
|
|
216
|
+
| `config` | no | Strategy-specific settings (see below) |
|
|
217
|
+
| `xHeaders` | no | Extra HTTP headers to capture during browser auth (see [xHeaders](#xheaders)) |
|
|
218
|
+
|
|
219
|
+
#### Strategy: `cookie`
|
|
220
|
+
|
|
221
|
+
For SSO-protected web apps. Opens a browser, waits for login, extracts cookies. This is the default strategy -- most sites need no config at all.
|
|
222
|
+
|
|
223
|
+
| Config field | Required | Default | Description |
|
|
224
|
+
|--------------|----------|---------|-------------|
|
|
225
|
+
| `ttl` | no | `24h` | How long cookies are considered valid before re-authentication. Duration string: `ms`, `s`, `m`, `h`, `d`. Examples: `30m`, `12h`, `7d` |
|
|
226
|
+
| `requiredCookies` | no | -- | Cookie names that must exist before auth is considered complete. Use for sites where the entry page isn't a login page (e.g. QR code login). Example: `["session_id", "id_token"]` |
|
|
227
|
+
|
|
228
|
+
```yaml
|
|
229
|
+
providers:
|
|
230
|
+
jira:
|
|
231
|
+
domains: ["jira.example.com"]
|
|
232
|
+
strategy: cookie
|
|
233
|
+
config:
|
|
234
|
+
ttl: "10d"
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Minimal (uses all defaults):
|
|
238
|
+
```yaml
|
|
239
|
+
providers:
|
|
240
|
+
jira:
|
|
241
|
+
domains: ["jira.example.com"]
|
|
242
|
+
strategy: cookie
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### Strategy: `oauth2`
|
|
246
|
+
|
|
247
|
+
For APIs using OAuth2/JWT tokens. Opens a browser for the OAuth consent flow, extracts tokens from browser localStorage.
|
|
248
|
+
|
|
249
|
+
| Config field | Required | Default | Description |
|
|
250
|
+
|--------------|----------|---------|-------------|
|
|
251
|
+
| `audiences` | no | -- | Filter tokens by audience claim. Only tokens matching these audiences are extracted. Example: `["https://graph.microsoft.com"]` |
|
|
252
|
+
| `tokenEndpoint` | no | -- | Token endpoint URL for refresh_token grant. Required if you want automatic token refresh |
|
|
253
|
+
| `clientId` | no | -- | OAuth2 client ID for refresh_token grant. Required with `tokenEndpoint` |
|
|
254
|
+
| `scopes` | no | -- | OAuth2 scopes for refresh_token grant. Example: `["openid", "profile", "User.Read"]` |
|
|
255
|
+
|
|
256
|
+
```yaml
|
|
257
|
+
providers:
|
|
258
|
+
ms-teams:
|
|
259
|
+
name: Microsoft Teams
|
|
260
|
+
domains: ["teams.cloud.microsoft"]
|
|
261
|
+
entryUrl: https://teams.cloud.microsoft/v2/
|
|
262
|
+
strategy: oauth2
|
|
263
|
+
config:
|
|
264
|
+
audiences: ["https://ic3.teams.office.com"]
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
#### Strategy: `api-token`
|
|
268
|
+
|
|
269
|
+
For static API keys or personal access tokens. No browser needed -- prompts the user to enter a token.
|
|
270
|
+
|
|
271
|
+
| Config field | Required | Default | Description |
|
|
272
|
+
|--------------|----------|---------|-------------|
|
|
273
|
+
| `headerName` | no | `Authorization` | HTTP header name to place the token in |
|
|
274
|
+
| `headerPrefix` | no | `Bearer` | Prefix before the token value. Set to empty string for no prefix |
|
|
275
|
+
| `setupInstructions` | no | -- | Instructions shown to the user when a token is needed. Supports multi-line |
|
|
276
|
+
|
|
277
|
+
```yaml
|
|
278
|
+
providers:
|
|
279
|
+
github:
|
|
280
|
+
name: GitHub
|
|
281
|
+
domains: ["github.com", "api.github.com"]
|
|
282
|
+
strategy: api-token
|
|
283
|
+
config:
|
|
284
|
+
headerName: Authorization
|
|
285
|
+
headerPrefix: Bearer
|
|
286
|
+
setupInstructions: |
|
|
287
|
+
Create a Personal Access Token at:
|
|
288
|
+
https://github.com/settings/tokens
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### Strategy: `basic`
|
|
292
|
+
|
|
293
|
+
For username/password authentication. No browser needed -- prompts the user for credentials.
|
|
294
|
+
|
|
295
|
+
| Config field | Required | Default | Description |
|
|
296
|
+
|--------------|----------|---------|-------------|
|
|
297
|
+
| `setupInstructions` | no | -- | Instructions shown to the user when credentials are needed |
|
|
298
|
+
|
|
299
|
+
```yaml
|
|
300
|
+
providers:
|
|
301
|
+
legacy-api:
|
|
302
|
+
domains: ["api.internal.corp"]
|
|
303
|
+
strategy: basic
|
|
304
|
+
config:
|
|
305
|
+
setupInstructions: "Contact IT for credentials."
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### xHeaders
|
|
309
|
+
|
|
310
|
+
Capture extra HTTP headers during browser authentication. Useful for APIs that require anti-bot signatures, CSRF tokens, or custom headers that are set dynamically by the web app.
|
|
311
|
+
|
|
312
|
+
Captured headers are stored alongside the credential and applied automatically on `sig get` and `sig request`.
|
|
313
|
+
|
|
314
|
+
| Field | Required | Description |
|
|
315
|
+
|-------|----------|-------------|
|
|
316
|
+
| `name` | **yes** | HTTP header name to capture (case-insensitive match) |
|
|
317
|
+
| `source` | no | Where to capture from: `request` or `response`. Default: both |
|
|
318
|
+
| `urlPattern` | no | Only capture from URLs matching this substring |
|
|
319
|
+
| `staticValue` | no | Use a fixed value instead of capturing dynamically. When set, `source` and `urlPattern` are ignored |
|
|
320
|
+
|
|
321
|
+
```yaml
|
|
322
|
+
providers:
|
|
323
|
+
my-app:
|
|
324
|
+
domains: ["app.example.com"]
|
|
325
|
+
entryUrl: https://app.example.com/
|
|
326
|
+
strategy: cookie
|
|
327
|
+
forceVisible: true
|
|
328
|
+
config:
|
|
329
|
+
requiredCookies: ["id_token"]
|
|
330
|
+
xHeaders:
|
|
331
|
+
- name: x-csrf-token
|
|
332
|
+
source: request
|
|
333
|
+
urlPattern: app.example.com/api
|
|
334
|
+
- name: origin
|
|
335
|
+
staticValue: https://app.example.com
|
|
336
|
+
- name: referer
|
|
337
|
+
staticValue: https://app.example.com/
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Full example
|
|
341
|
+
|
|
342
|
+
```yaml
|
|
343
|
+
browser:
|
|
344
|
+
browserDataDir: ~/.signet/browser-data
|
|
345
|
+
channel: chrome
|
|
346
|
+
headlessTimeout: 15000
|
|
347
|
+
visibleTimeout: 60000
|
|
348
|
+
waitUntil: load
|
|
349
|
+
|
|
350
|
+
storage:
|
|
351
|
+
credentialsDir: ~/.signet/credentials
|
|
352
|
+
|
|
353
|
+
remotes:
|
|
354
|
+
dev-server:
|
|
355
|
+
type: ssh
|
|
356
|
+
host: dev.example.com
|
|
357
|
+
user: deploy
|
|
358
|
+
|
|
359
|
+
providers:
|
|
360
|
+
jira:
|
|
361
|
+
domains: ["jira.example.com"]
|
|
362
|
+
strategy: cookie
|
|
363
|
+
config:
|
|
364
|
+
ttl: "10d"
|
|
365
|
+
|
|
366
|
+
github:
|
|
367
|
+
domains: ["github.com", "api.github.com"]
|
|
368
|
+
strategy: api-token
|
|
369
|
+
config:
|
|
370
|
+
setupInstructions: "Create a PAT at https://github.com/settings/tokens"
|
|
371
|
+
|
|
372
|
+
ms-teams:
|
|
373
|
+
domains: ["teams.cloud.microsoft"]
|
|
374
|
+
entryUrl: https://teams.cloud.microsoft/v2/
|
|
375
|
+
strategy: oauth2
|
|
376
|
+
config:
|
|
377
|
+
audiences: ["https://ic3.teams.office.com"]
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## Authentication Strategies
|
|
381
|
+
|
|
382
|
+
| Strategy | When to use | Browser needed |
|
|
383
|
+
|----------|-------------|----------------|
|
|
384
|
+
| **cookie** | SSO-protected web apps (default) | Yes |
|
|
385
|
+
| **oauth2** | APIs with OAuth2/JWT tokens | Yes |
|
|
386
|
+
| **api-token** | Static API keys or PATs | No |
|
|
387
|
+
| **basic** | Username/password auth | No |
|
|
388
|
+
|
|
389
|
+
Cookie-based auth is the default -- just `sig login <url>` and complete SSO in the browser window.
|
|
390
|
+
|
|
391
|
+
## License
|
|
392
|
+
|
|
393
|
+
[MIT](LICENSE)
|
package/bin/sig.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { dirname, join } from 'node:path';
|
|
6
|
+
import { execSync } from 'node:child_process';
|
|
7
|
+
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = dirname(__filename);
|
|
10
|
+
const rootDir = join(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
function getVersion() {
|
|
13
|
+
try {
|
|
14
|
+
const pkg = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf-8'));
|
|
15
|
+
return pkg.version || 'unknown';
|
|
16
|
+
} catch {
|
|
17
|
+
return 'unknown';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function buildIfNeeded() {
|
|
22
|
+
const distPath = join(rootDir, 'dist', 'index.js');
|
|
23
|
+
if (!existsSync(distPath)) {
|
|
24
|
+
// If no .git directory, this is likely a global install with missing dist/
|
|
25
|
+
const gitDir = join(rootDir, '.git');
|
|
26
|
+
if (!existsSync(gitDir)) {
|
|
27
|
+
console.error('[signet] dist/ directory is missing and this is not a dev checkout.');
|
|
28
|
+
console.error('[signet] Please reinstall: npm install -g signet-auth');
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Dev checkout: build from source
|
|
33
|
+
console.error('[signet] Building project...');
|
|
34
|
+
try {
|
|
35
|
+
execSync('npm run build', { cwd: rootDir, stdio: 'inherit' });
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.error('[signet] Build failed:', e.message);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function main() {
|
|
44
|
+
const args = process.argv.slice(2);
|
|
45
|
+
|
|
46
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
47
|
+
console.log(getVersion());
|
|
48
|
+
process.exit(0);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
buildIfNeeded();
|
|
52
|
+
|
|
53
|
+
const { run } = await import(join(rootDir, 'dist', 'cli', 'main.js'));
|
|
54
|
+
await run(args);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Graceful shutdown
|
|
58
|
+
process.on('SIGINT', () => process.exit(0));
|
|
59
|
+
process.on('SIGTERM', () => process.exit(0));
|
|
60
|
+
process.on('unhandledRejection', (err) => {
|
|
61
|
+
console.error('[signet] Unhandled rejection:', err);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
main();
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import type { IBrowserAdapter } from './core/interfaces/browser-adapter.js';
|
|
2
|
+
import type { IStorage } from './core/interfaces/storage.js';
|
|
3
|
+
import type { IProviderRegistry } from './core/interfaces/provider.js';
|
|
4
|
+
import type { Credential, ProviderConfig, ProviderStatus, ILogger } from './core/types.js';
|
|
5
|
+
import type { BrowserConfig } from './config/schema.js';
|
|
6
|
+
import type { Result } from './core/result.js';
|
|
7
|
+
import { type AuthError } from './core/errors.js';
|
|
8
|
+
import { StrategyRegistry } from './strategies/registry.js';
|
|
9
|
+
export interface AuthManagerDeps {
|
|
10
|
+
storage: IStorage;
|
|
11
|
+
strategyRegistry: StrategyRegistry;
|
|
12
|
+
providerRegistry: IProviderRegistry;
|
|
13
|
+
browserAdapterFactory: () => IBrowserAdapter;
|
|
14
|
+
browserConfig: BrowserConfig;
|
|
15
|
+
logger?: ILogger;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Central orchestrator for authentication lifecycle.
|
|
19
|
+
* All dependencies are injected — no singletons, no global state.
|
|
20
|
+
*
|
|
21
|
+
* Flow: validate → refresh → authenticate
|
|
22
|
+
*/
|
|
23
|
+
export declare class AuthManager {
|
|
24
|
+
private readonly storage;
|
|
25
|
+
private readonly strategies;
|
|
26
|
+
private readonly providers;
|
|
27
|
+
private readonly browserAdapterFactory;
|
|
28
|
+
private readonly browserConfig;
|
|
29
|
+
private readonly logger?;
|
|
30
|
+
constructor(deps: AuthManagerDeps);
|
|
31
|
+
/**
|
|
32
|
+
* Get valid credentials for a provider.
|
|
33
|
+
* Tries: stored → refresh → authenticate, in that order.
|
|
34
|
+
*/
|
|
35
|
+
getCredentials(providerId: string): Promise<Result<Credential, AuthError>>;
|
|
36
|
+
/**
|
|
37
|
+
* Resolve a provider by URL, auto-provisioning a default cookie provider if none matches.
|
|
38
|
+
*/
|
|
39
|
+
resolveProvider(url: string): ProviderConfig;
|
|
40
|
+
/**
|
|
41
|
+
* Get credentials for a specific provider, resolving by URL.
|
|
42
|
+
*/
|
|
43
|
+
getCredentialsByUrl(url: string): Promise<Result<{
|
|
44
|
+
provider: ProviderConfig;
|
|
45
|
+
credential: Credential;
|
|
46
|
+
}, AuthError>>;
|
|
47
|
+
/**
|
|
48
|
+
* Force re-authentication, deleting any stored credentials first.
|
|
49
|
+
*/
|
|
50
|
+
forceReauth(providerId: string): Promise<Result<Credential, AuthError>>;
|
|
51
|
+
/**
|
|
52
|
+
* Store a credential directly (e.g., user-provided API token).
|
|
53
|
+
*/
|
|
54
|
+
setCredential(providerId: string, credential: Credential): Promise<Result<void, AuthError>>;
|
|
55
|
+
/**
|
|
56
|
+
* Get status for a provider (non-triggering — won't start auth).
|
|
57
|
+
*/
|
|
58
|
+
getStatus(providerId: string): Promise<ProviderStatus>;
|
|
59
|
+
/**
|
|
60
|
+
* Get status for all configured providers.
|
|
61
|
+
*/
|
|
62
|
+
getAllStatus(): Promise<ProviderStatus[]>;
|
|
63
|
+
/**
|
|
64
|
+
* Clear stored credentials for a provider.
|
|
65
|
+
*/
|
|
66
|
+
clearCredentials(providerId: string): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* Clear all stored credentials.
|
|
69
|
+
*/
|
|
70
|
+
clearAll(): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Apply credentials to an outgoing request (as headers).
|
|
73
|
+
*/
|
|
74
|
+
applyToRequest(providerId: string, credential: Credential): Record<string, string>;
|
|
75
|
+
/**
|
|
76
|
+
* Validate a credential by making a test request to the provider's entry URL.
|
|
77
|
+
* Returns the HTTP status and whether the response redirects to a login page.
|
|
78
|
+
*/
|
|
79
|
+
validateCredential(provider: ProviderConfig, credential: Credential): Promise<{
|
|
80
|
+
status: number | null;
|
|
81
|
+
isLoginRedirect: boolean;
|
|
82
|
+
}>;
|
|
83
|
+
/** Expose the provider registry for handlers */
|
|
84
|
+
get providerRegistry(): IProviderRegistry;
|
|
85
|
+
/** Storage key: uses credentialFile if configured, otherwise provider ID. */
|
|
86
|
+
private storageKey;
|
|
87
|
+
private checkCredentialType;
|
|
88
|
+
private store;
|
|
89
|
+
private getExpiresAt;
|
|
90
|
+
}
|