grok-it-mcp 0.1.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/README.md +106 -0
- package/dist/auth/credentials.d.ts +28 -0
- package/dist/auth/credentials.js +67 -0
- package/dist/auth/credentials.js.map +1 -0
- package/dist/auth/oauth.d.ts +101 -0
- package/dist/auth/oauth.js +284 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/cache/artifacts.d.ts +16 -0
- package/dist/cache/artifacts.js +62 -0
- package/dist/cache/artifacts.js.map +1 -0
- package/dist/cli.d.ts +19 -0
- package/dist/cli.js +278 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/constants.d.ts +18 -0
- package/dist/config/constants.js +19 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/config/env.d.ts +11 -0
- package/dist/config/env.js +17 -0
- package/dist/config/env.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.js +67 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/tools/image-generate.d.ts +41 -0
- package/dist/tools/image-generate.js +45 -0
- package/dist/tools/image-generate.js.map +1 -0
- package/dist/tools/video-generate.d.ts +66 -0
- package/dist/tools/video-generate.js +89 -0
- package/dist/tools/video-generate.js.map +1 -0
- package/dist/tools/x-search.d.ts +27 -0
- package/dist/tools/x-search.js +48 -0
- package/dist/tools/x-search.js.map +1 -0
- package/dist/xai/client.d.ts +25 -0
- package/dist/xai/client.js +77 -0
- package/dist/xai/client.js.map +1 -0
- package/package.json +36 -0
- package/plugins/grok-it/.claude-plugin/plugin.json +12 -0
- package/plugins/grok-it/.codex-plugin/plugin.json +37 -0
- package/plugins/grok-it/.mcp.json +15 -0
- package/plugins/grok-it/skills/grok-tools/SKILL.md +16 -0
- package/plugins/grok-it/skills/grok-tools/agents/openai.yaml +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# grok-it MCP Plugin
|
|
2
|
+
|
|
3
|
+
Local TypeScript stdio MCP server published as an npm CLI package, plus shared Claude Code + Codex plugin wrappers for Grok/xAI.
|
|
4
|
+
|
|
5
|
+
- `grok_x_search` — xAI Responses API with built-in `x_search`.
|
|
6
|
+
- `grok_image_generate` — `/images/generations`, cached locally by default.
|
|
7
|
+
- `grok_video_generate` — `/videos/generations`, polling; returns remote URL by default, optional local cache.
|
|
8
|
+
- `grok_auth_status` / `grok_login` — Grok OAuth PKCE status/login with `XAI_API_KEY` fallback.
|
|
9
|
+
|
|
10
|
+
## npm CLI
|
|
11
|
+
|
|
12
|
+
Install the server directly:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install -g grok-it-mcp
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or run it ad hoc:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx -y grok-it-mcp@0.1.0
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The default CLI starts the stdio MCP server defined in `src/index.ts`. It also exposes auth helpers for terminal use:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
grok-it-mcp status
|
|
28
|
+
grok-it-mcp login --open
|
|
29
|
+
grok-it-mcp search "xAI news"
|
|
30
|
+
grok-it-mcp x-search "grok updates" --include-handles xai --max-results 5 --json
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
For manual OAuth completion without a loopback browser flow:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
grok-it-mcp login
|
|
37
|
+
grok-it-mcp login --callback '<callback-url-or-code>' --verifier '<verifier>' --state '<state>' --redirect-uri 'http://127.0.0.1:8765/callback'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### OAuth note
|
|
42
|
+
|
|
43
|
+
The current default browser-login flow uses xAI's public Grok OAuth client id and the `grok-cli:access api:access` scopes. If xAI changes those values again, override them with `GROK_IT_OAUTH_CLIENT_ID` or fall back to `XAI_API_KEY`.
|
|
44
|
+
|
|
45
|
+
### Search connectivity test
|
|
46
|
+
|
|
47
|
+
Use `search` or its alias `x-search` to run the existing `grok_x_search` flow from a terminal. This is useful for end-to-end connectivity checks because it exercises credential resolution, xAI `/responses`, and the built-in `x_search` tool:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
grok-it-mcp search "xAI news"
|
|
51
|
+
grok-it-mcp x-search --query "grok updates" --include-handles xai,elonmusk --max-results 10 --json
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Supported search flags: `--model`, `--from-date`, `--to-date`, `--include-handles`, `--exclude-handles`, `--include-images`, `--include-videos`, `--max-results`, and `--json`.
|
|
55
|
+
## Cross-platform plugin root
|
|
56
|
+
|
|
57
|
+
`plugins/grok-it/` is the canonical plugin root for both Claude Code and Codex:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
plugins/grok-it/
|
|
61
|
+
.claude-plugin/plugin.json # Claude Code manifest
|
|
62
|
+
.codex-plugin/plugin.json # Codex manifest
|
|
63
|
+
.mcp.json # shared MCP server config
|
|
64
|
+
skills/grok-tools/SKILL.md # shared skill instructions
|
|
65
|
+
skills/grok-tools/agents/openai.yaml
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Both manifests reference the same `./skills/` and `./.mcp.json`. The shared MCP config launches `npx -y grok-it-mcp@0.1.0`, so the plugin no longer bundles `dist/index.js`.
|
|
69
|
+
|
|
70
|
+
## Install/build
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
npm install
|
|
74
|
+
npm run build
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
`npm run build` typechecks and emits the CLI entrypoint.
|
|
78
|
+
|
|
79
|
+
## Authentication
|
|
80
|
+
|
|
81
|
+
Preferred: call MCP tool `grok_login`. It performs OAuth PKCE and stores tokens at `~/.grok-it/auth.json` (override with `GROK_IT_TOKEN_STORE`). The tool never returns token material.
|
|
82
|
+
|
|
83
|
+
Fallback: set `XAI_API_KEY`. OAuth credentials take precedence over API keys. OAuth bearer requests are pinned to `https://*.x.ai` so `XAI_BASE_URL` cannot leak OAuth tokens to another origin.
|
|
84
|
+
|
|
85
|
+
## Codex
|
|
86
|
+
|
|
87
|
+
Install/use `plugins/grok-it/` as the Codex plugin root. The Codex manifest is at `plugins/grok-it/.codex-plugin/plugin.json`.
|
|
88
|
+
|
|
89
|
+
## Claude Code
|
|
90
|
+
|
|
91
|
+
Install/use the same `plugins/grok-it/` folder as the Claude Code plugin root. The Claude manifest is at `plugins/grok-it/.claude-plugin/plugin.json`.
|
|
92
|
+
|
|
93
|
+
## Validation
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm run typecheck
|
|
97
|
+
npm test
|
|
98
|
+
npm run build
|
|
99
|
+
npm run validate:plugin
|
|
100
|
+
npm run validate:codex-plugin
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- `validate:plugin` checks the shared Claude/Codex plugin root and shared MCP config.
|
|
104
|
+
- `validate:codex-plugin` runs the official plugin-creator validator against `plugins/grok-it/` and checks shared skill metadata.
|
|
105
|
+
|
|
106
|
+
Tests mock network behavior; they must not call real xAI APIs or open browsers.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type CredentialSource = 'xai-oauth' | 'xai';
|
|
2
|
+
export type ResolvedCredentials = {
|
|
3
|
+
provider: CredentialSource;
|
|
4
|
+
credentialSource: CredentialSource;
|
|
5
|
+
authorization: string;
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
expiresAt?: number;
|
|
8
|
+
tokenStorePath?: string;
|
|
9
|
+
};
|
|
10
|
+
export declare class AuthRequiredError extends Error {
|
|
11
|
+
constructor(message?: string);
|
|
12
|
+
}
|
|
13
|
+
export declare function resolveCredentials(options?: {
|
|
14
|
+
forceRefresh?: boolean;
|
|
15
|
+
fetchImpl?: typeof fetch;
|
|
16
|
+
env?: NodeJS.ProcessEnv;
|
|
17
|
+
}): Promise<ResolvedCredentials>;
|
|
18
|
+
export declare function isOAuthCredential(creds: ResolvedCredentials): boolean;
|
|
19
|
+
export declare function redactSecret(input: string): string;
|
|
20
|
+
export declare function authStatus(env?: NodeJS.ProcessEnv): Promise<{
|
|
21
|
+
logged_in: boolean;
|
|
22
|
+
provider: string | null;
|
|
23
|
+
base_url: string | null;
|
|
24
|
+
oauth_expires_at: string | null;
|
|
25
|
+
token_store: string;
|
|
26
|
+
cache_dir: string;
|
|
27
|
+
api_key_present: boolean;
|
|
28
|
+
}>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { DEFAULT_XAI_BASE_URL } from '../config/constants.js';
|
|
2
|
+
import { getConfig } from '../config/env.js';
|
|
3
|
+
import { OAuthError, readOAuthState, refreshOAuthState, validateInferenceBaseUrl } from './oauth.js';
|
|
4
|
+
export class AuthRequiredError extends Error {
|
|
5
|
+
constructor(message = 'No Grok OAuth token or XAI_API_KEY is configured') {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'AuthRequiredError';
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
export async function resolveCredentials(options = {}) {
|
|
11
|
+
const config = getConfig(options.env);
|
|
12
|
+
const oauth = await readOAuthState(config.tokenStorePath);
|
|
13
|
+
if (oauth) {
|
|
14
|
+
try {
|
|
15
|
+
const fresh = await refreshOAuthState(oauth, { force: options.forceRefresh, fetchImpl: options.fetchImpl, tokenStorePath: config.tokenStorePath });
|
|
16
|
+
return {
|
|
17
|
+
provider: 'xai-oauth',
|
|
18
|
+
credentialSource: 'xai-oauth',
|
|
19
|
+
authorization: `Bearer ${fresh.tokens.access_token}`,
|
|
20
|
+
baseUrl: validateInferenceBaseUrl(fresh.base_url || DEFAULT_XAI_BASE_URL),
|
|
21
|
+
expiresAt: fresh.tokens.expires_at,
|
|
22
|
+
tokenStorePath: config.tokenStorePath,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof OAuthError && (error.code === 'invalid_grant' || error.code === 'oauth_entitlement_required')) {
|
|
27
|
+
if (config.apiKey)
|
|
28
|
+
return apiKeyCredentials(config);
|
|
29
|
+
}
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (config.apiKey)
|
|
34
|
+
return apiKeyCredentials(config);
|
|
35
|
+
throw new AuthRequiredError();
|
|
36
|
+
}
|
|
37
|
+
function apiKeyCredentials(config) {
|
|
38
|
+
return {
|
|
39
|
+
provider: 'xai',
|
|
40
|
+
credentialSource: 'xai',
|
|
41
|
+
authorization: `Bearer ${config.apiKey}`,
|
|
42
|
+
baseUrl: config.baseUrl.replace(/\/$/, ''),
|
|
43
|
+
tokenStorePath: config.tokenStorePath,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function isOAuthCredential(creds) {
|
|
47
|
+
return creds.provider === 'xai-oauth';
|
|
48
|
+
}
|
|
49
|
+
export function redactSecret(input) {
|
|
50
|
+
return input
|
|
51
|
+
.replace(/Bearer\s+[A-Za-z0-9._~+/-]+/g, 'Bearer [REDACTED]')
|
|
52
|
+
.replace(/(access_token|refresh_token|id_token|code|code_verifier)=([^&\s]+)/gi, '$1=[REDACTED]');
|
|
53
|
+
}
|
|
54
|
+
export async function authStatus(env = process.env) {
|
|
55
|
+
const config = getConfig(env);
|
|
56
|
+
const oauth = await readOAuthState(config.tokenStorePath);
|
|
57
|
+
return {
|
|
58
|
+
logged_in: Boolean(oauth?.tokens?.access_token || config.apiKey),
|
|
59
|
+
provider: oauth?.tokens?.access_token ? 'xai-oauth' : config.apiKey ? 'xai' : null,
|
|
60
|
+
base_url: oauth?.tokens?.access_token ? oauth.base_url : config.apiKey ? config.baseUrl : null,
|
|
61
|
+
oauth_expires_at: oauth?.tokens?.expires_at ? new Date(oauth.tokens.expires_at).toISOString() : null,
|
|
62
|
+
token_store: config.tokenStorePath,
|
|
63
|
+
cache_dir: config.cacheDir,
|
|
64
|
+
api_key_present: Boolean(config.apiKey),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/auth/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAarG,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAO,GAAG,kDAAkD;QACtE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,UAAyF,EAAE;IAClI,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAC1D,IAAI,KAAK,EAAE,CAAC;QACV,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,YAAY,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;YACnJ,OAAO;gBACL,QAAQ,EAAE,WAAW;gBACrB,gBAAgB,EAAE,WAAW;gBAC7B,aAAa,EAAE,UAAU,KAAK,CAAC,MAAM,CAAC,YAAY,EAAE;gBACpD,OAAO,EAAE,wBAAwB,CAAC,KAAK,CAAC,QAAQ,IAAI,oBAAoB,CAAC;gBACzE,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;gBAClC,cAAc,EAAE,MAAM,CAAC,cAAc;aACtC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,UAAU,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,KAAK,CAAC,IAAI,KAAK,4BAA4B,CAAC,EAAE,CAAC;gBACnH,IAAI,MAAM,CAAC,MAAM;oBAAE,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;YACtD,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IACD,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACpD,MAAM,IAAI,iBAAiB,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAoC;IAC7D,OAAO;QACL,QAAQ,EAAE,KAAK;QACf,gBAAgB,EAAE,KAAK;QACvB,aAAa,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE;QACxC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QAC1C,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,KAA0B;IAC1D,OAAO,KAAK,CAAC,QAAQ,KAAK,WAAW,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,KAAK;SACT,OAAO,CAAC,8BAA8B,EAAE,mBAAmB,CAAC;SAC5D,OAAO,CAAC,sEAAsE,EAAE,eAAe,CAAC,CAAC;AACtG,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IACnE,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IAC1D,OAAO;QACL,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,IAAI,MAAM,CAAC,MAAM,CAAC;QAChE,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;QAClF,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI;QAC9F,gBAAgB,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI;QACpG,WAAW,EAAE,MAAM,CAAC,cAAc;QAClC,SAAS,EAAE,MAAM,CAAC,QAAQ;QAC1B,eAAe,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;KACxC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export type OAuthDiscovery = {
|
|
2
|
+
issuer?: string;
|
|
3
|
+
authorization_endpoint: string;
|
|
4
|
+
token_endpoint: string;
|
|
5
|
+
};
|
|
6
|
+
export type StoredOAuthTokens = {
|
|
7
|
+
access_token: string;
|
|
8
|
+
refresh_token?: string;
|
|
9
|
+
id_token?: string;
|
|
10
|
+
expires_at?: number;
|
|
11
|
+
token_type?: string;
|
|
12
|
+
scope?: string;
|
|
13
|
+
};
|
|
14
|
+
export type StoredOAuthState = {
|
|
15
|
+
provider: 'xai-oauth';
|
|
16
|
+
auth_mode: 'oauth_pkce';
|
|
17
|
+
tokens: StoredOAuthTokens;
|
|
18
|
+
discovery: OAuthDiscovery;
|
|
19
|
+
redirect_uri: string;
|
|
20
|
+
base_url: string;
|
|
21
|
+
last_refresh: string;
|
|
22
|
+
invalid?: boolean;
|
|
23
|
+
last_auth_error?: string;
|
|
24
|
+
};
|
|
25
|
+
export type AuthStore = {
|
|
26
|
+
providers?: {
|
|
27
|
+
'xai-oauth'?: StoredOAuthState;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export type LoginSession = {
|
|
31
|
+
verifier: string;
|
|
32
|
+
challenge: string;
|
|
33
|
+
state: string;
|
|
34
|
+
nonce: string;
|
|
35
|
+
redirectUri: string;
|
|
36
|
+
authorizeUrl: string;
|
|
37
|
+
discovery: OAuthDiscovery;
|
|
38
|
+
};
|
|
39
|
+
export declare class OAuthError extends Error {
|
|
40
|
+
code: string;
|
|
41
|
+
status?: number | undefined;
|
|
42
|
+
constructor(code: string, message: string, status?: number | undefined);
|
|
43
|
+
}
|
|
44
|
+
export declare function base64Url(input: Buffer): string;
|
|
45
|
+
export declare function generatePkce(): {
|
|
46
|
+
verifier: string;
|
|
47
|
+
challenge: string;
|
|
48
|
+
};
|
|
49
|
+
export declare function randomState(): string;
|
|
50
|
+
export declare function isXaiOrigin(value: string): boolean;
|
|
51
|
+
export declare function validateXaiHttpsUrl(value: string, label?: string): string;
|
|
52
|
+
export declare function validateInferenceBaseUrl(value: string): string;
|
|
53
|
+
export declare function readAuthStore(tokenStorePath?: string): Promise<AuthStore>;
|
|
54
|
+
export declare function writeAuthStore(store: AuthStore, tokenStorePath?: string): Promise<void>;
|
|
55
|
+
export declare function readOAuthState(tokenStorePath?: string): Promise<StoredOAuthState | undefined>;
|
|
56
|
+
export declare function saveOAuthState(state: StoredOAuthState, tokenStorePath?: string): Promise<void>;
|
|
57
|
+
export declare function markOAuthInvalid(reason: string, tokenStorePath?: string): Promise<void>;
|
|
58
|
+
export declare function clearOAuthState(tokenStorePath?: string): Promise<void>;
|
|
59
|
+
export declare function tokenExpiresAt(tokenResponse: Record<string, unknown>, now?: number): number | undefined;
|
|
60
|
+
export declare function isTokenExpiring(tokens: StoredOAuthTokens, now?: number): boolean;
|
|
61
|
+
export declare function discoverOAuth(fetchImpl?: typeof fetch): Promise<OAuthDiscovery>;
|
|
62
|
+
export declare function buildAuthorizeUrl(params: {
|
|
63
|
+
discovery: OAuthDiscovery;
|
|
64
|
+
clientId?: string;
|
|
65
|
+
redirectUri: string;
|
|
66
|
+
scope?: string;
|
|
67
|
+
challenge: string;
|
|
68
|
+
state: string;
|
|
69
|
+
nonce: string;
|
|
70
|
+
}): string;
|
|
71
|
+
export declare function createLoginSession(options?: {
|
|
72
|
+
redirectUri?: string;
|
|
73
|
+
port?: number;
|
|
74
|
+
fetchImpl?: typeof fetch;
|
|
75
|
+
}): Promise<LoginSession>;
|
|
76
|
+
export declare function parseCallback(input: string, expectedState?: string): {
|
|
77
|
+
code: string;
|
|
78
|
+
state?: string;
|
|
79
|
+
};
|
|
80
|
+
export declare function exchangeCodeForTokens(params: {
|
|
81
|
+
code: string;
|
|
82
|
+
verifier: string;
|
|
83
|
+
challenge?: string;
|
|
84
|
+
redirectUri: string;
|
|
85
|
+
discovery: OAuthDiscovery;
|
|
86
|
+
clientId?: string;
|
|
87
|
+
fetchImpl?: typeof fetch;
|
|
88
|
+
}): Promise<StoredOAuthTokens>;
|
|
89
|
+
export declare function persistTokenResponse(params: {
|
|
90
|
+
tokens: StoredOAuthTokens;
|
|
91
|
+
discovery: OAuthDiscovery;
|
|
92
|
+
redirectUri: string;
|
|
93
|
+
baseUrl?: string;
|
|
94
|
+
tokenStorePath?: string;
|
|
95
|
+
}): Promise<StoredOAuthState>;
|
|
96
|
+
export declare function refreshOAuthState(state: StoredOAuthState, options?: {
|
|
97
|
+
force?: boolean;
|
|
98
|
+
fetchImpl?: typeof fetch;
|
|
99
|
+
tokenStorePath?: string;
|
|
100
|
+
}): Promise<StoredOAuthState>;
|
|
101
|
+
export declare function waitForLoopbackCode(session: LoginSession, timeoutMs: number): Promise<string>;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import crypto from 'node:crypto';
|
|
2
|
+
import http from 'node:http';
|
|
3
|
+
import { URL, URLSearchParams } from 'node:url';
|
|
4
|
+
import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { DEFAULT_REDIRECT_HOST, DEFAULT_REDIRECT_PATH, DEFAULT_REDIRECT_PORT, DEFAULT_XAI_DISCOVERY_URL, DEFAULT_XAI_OAUTH_CLIENT_ID, DEFAULT_XAI_OAUTH_SCOPE, OAUTH_REFRESH_SKEW_MS, PACKAGE_NAME, PACKAGE_VERSION, } from '../config/constants.js';
|
|
7
|
+
import { getConfig } from '../config/env.js';
|
|
8
|
+
export class OAuthError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
status;
|
|
11
|
+
constructor(code, message, status) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.status = status;
|
|
15
|
+
this.name = 'OAuthError';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function base64Url(input) {
|
|
19
|
+
return input.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
|
|
20
|
+
}
|
|
21
|
+
export function generatePkce() {
|
|
22
|
+
const verifier = base64Url(crypto.randomBytes(32));
|
|
23
|
+
const challenge = base64Url(crypto.createHash('sha256').update(verifier).digest());
|
|
24
|
+
return { verifier, challenge };
|
|
25
|
+
}
|
|
26
|
+
export function randomState() {
|
|
27
|
+
return base64Url(crypto.randomBytes(24));
|
|
28
|
+
}
|
|
29
|
+
export function isXaiOrigin(value) {
|
|
30
|
+
try {
|
|
31
|
+
const url = new URL(value);
|
|
32
|
+
return url.protocol === 'https:' && (url.hostname === 'x.ai' || url.hostname.endsWith('.x.ai'));
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export function validateXaiHttpsUrl(value, label = 'xAI URL') {
|
|
39
|
+
if (!isXaiOrigin(value)) {
|
|
40
|
+
throw new OAuthError('xai_origin_required', `${label} must be an https://*.x.ai URL`);
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
export function validateInferenceBaseUrl(value) {
|
|
45
|
+
const url = new URL(validateXaiHttpsUrl(value, 'OAuth inference base URL'));
|
|
46
|
+
url.pathname = url.pathname.replace(/\/$/, '');
|
|
47
|
+
return url.toString().replace(/\/$/, '');
|
|
48
|
+
}
|
|
49
|
+
export async function readAuthStore(tokenStorePath = getConfig().tokenStorePath) {
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(await readFile(tokenStorePath, 'utf8'));
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (error.code === 'ENOENT')
|
|
55
|
+
return {};
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export async function writeAuthStore(store, tokenStorePath = getConfig().tokenStorePath) {
|
|
60
|
+
await mkdir(path.dirname(tokenStorePath), { recursive: true, mode: 0o700 });
|
|
61
|
+
const tmp = `${tokenStorePath}.${process.pid}.tmp`;
|
|
62
|
+
await writeFile(tmp, `${JSON.stringify(store, null, 2)}\n`, { mode: 0o600 });
|
|
63
|
+
await rename(tmp, tokenStorePath);
|
|
64
|
+
}
|
|
65
|
+
export async function readOAuthState(tokenStorePath = getConfig().tokenStorePath) {
|
|
66
|
+
const state = (await readAuthStore(tokenStorePath)).providers?.['xai-oauth'];
|
|
67
|
+
if (!state || state.invalid || !state.tokens?.access_token)
|
|
68
|
+
return undefined;
|
|
69
|
+
return state;
|
|
70
|
+
}
|
|
71
|
+
export async function saveOAuthState(state, tokenStorePath = getConfig().tokenStorePath) {
|
|
72
|
+
const store = await readAuthStore(tokenStorePath);
|
|
73
|
+
store.providers ||= {};
|
|
74
|
+
store.providers['xai-oauth'] = state;
|
|
75
|
+
await writeAuthStore(store, tokenStorePath);
|
|
76
|
+
}
|
|
77
|
+
export async function markOAuthInvalid(reason, tokenStorePath = getConfig().tokenStorePath) {
|
|
78
|
+
const store = await readAuthStore(tokenStorePath);
|
|
79
|
+
if (store.providers?.['xai-oauth']) {
|
|
80
|
+
store.providers['xai-oauth'].invalid = true;
|
|
81
|
+
store.providers['xai-oauth'].last_auth_error = reason;
|
|
82
|
+
await writeAuthStore(store, tokenStorePath);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export async function clearOAuthState(tokenStorePath = getConfig().tokenStorePath) {
|
|
86
|
+
const store = await readAuthStore(tokenStorePath);
|
|
87
|
+
if (store.providers?.['xai-oauth']) {
|
|
88
|
+
delete store.providers['xai-oauth'];
|
|
89
|
+
await writeAuthStore(store, tokenStorePath);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
await rm(tokenStorePath, { force: true });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export function tokenExpiresAt(tokenResponse, now = Date.now()) {
|
|
96
|
+
if (typeof tokenResponse.expires_at === 'number')
|
|
97
|
+
return tokenResponse.expires_at;
|
|
98
|
+
if (typeof tokenResponse.expires_in === 'number')
|
|
99
|
+
return now + tokenResponse.expires_in * 1000;
|
|
100
|
+
return undefined;
|
|
101
|
+
}
|
|
102
|
+
export function isTokenExpiring(tokens, now = Date.now()) {
|
|
103
|
+
return typeof tokens.expires_at === 'number' && tokens.expires_at - now <= OAUTH_REFRESH_SKEW_MS;
|
|
104
|
+
}
|
|
105
|
+
export async function discoverOAuth(fetchImpl = fetch) {
|
|
106
|
+
const response = await fetchImpl(DEFAULT_XAI_DISCOVERY_URL, { headers: { accept: 'application/json', 'user-agent': `${PACKAGE_NAME}/${PACKAGE_VERSION}` } });
|
|
107
|
+
if (!response.ok)
|
|
108
|
+
throw new OAuthError('discovery_failed', `OIDC discovery failed with HTTP ${response.status}`, response.status);
|
|
109
|
+
const discovery = (await response.json());
|
|
110
|
+
validateXaiHttpsUrl(discovery.authorization_endpoint, 'authorization_endpoint');
|
|
111
|
+
validateXaiHttpsUrl(discovery.token_endpoint, 'token_endpoint');
|
|
112
|
+
return discovery;
|
|
113
|
+
}
|
|
114
|
+
export function buildAuthorizeUrl(params) {
|
|
115
|
+
const url = new URL(params.discovery.authorization_endpoint);
|
|
116
|
+
url.search = new URLSearchParams({
|
|
117
|
+
response_type: 'code',
|
|
118
|
+
client_id: params.clientId || DEFAULT_XAI_OAUTH_CLIENT_ID,
|
|
119
|
+
redirect_uri: params.redirectUri,
|
|
120
|
+
scope: params.scope || DEFAULT_XAI_OAUTH_SCOPE,
|
|
121
|
+
code_challenge: params.challenge,
|
|
122
|
+
code_challenge_method: 'S256',
|
|
123
|
+
state: params.state,
|
|
124
|
+
nonce: params.nonce,
|
|
125
|
+
plan: 'generic',
|
|
126
|
+
referrer: PACKAGE_NAME,
|
|
127
|
+
}).toString();
|
|
128
|
+
return url.toString();
|
|
129
|
+
}
|
|
130
|
+
export async function createLoginSession(options = {}) {
|
|
131
|
+
const config = getConfig();
|
|
132
|
+
const discovery = await discoverOAuth(options.fetchImpl || fetch);
|
|
133
|
+
const { verifier, challenge } = generatePkce();
|
|
134
|
+
const state = randomState();
|
|
135
|
+
const nonce = randomState();
|
|
136
|
+
const redirectUri = options.redirectUri || `http://${DEFAULT_REDIRECT_HOST}:${options.port || DEFAULT_REDIRECT_PORT}${DEFAULT_REDIRECT_PATH}`;
|
|
137
|
+
return {
|
|
138
|
+
verifier,
|
|
139
|
+
challenge,
|
|
140
|
+
state,
|
|
141
|
+
nonce,
|
|
142
|
+
redirectUri,
|
|
143
|
+
discovery,
|
|
144
|
+
authorizeUrl: buildAuthorizeUrl({ discovery, clientId: config.oauthClientId, redirectUri, challenge, state, nonce }),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
export function parseCallback(input, expectedState) {
|
|
148
|
+
let code = null;
|
|
149
|
+
let state = null;
|
|
150
|
+
let callbackUrl = false;
|
|
151
|
+
if (/^https?:\/\//.test(input)) {
|
|
152
|
+
callbackUrl = true;
|
|
153
|
+
const url = new URL(input);
|
|
154
|
+
const error = url.searchParams.get('error');
|
|
155
|
+
if (error)
|
|
156
|
+
throw new OAuthError(error, url.searchParams.get('error_description') || error);
|
|
157
|
+
code = url.searchParams.get('code');
|
|
158
|
+
state = url.searchParams.get('state');
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
code = input.trim();
|
|
162
|
+
}
|
|
163
|
+
if (!code)
|
|
164
|
+
throw new OAuthError('missing_code', 'OAuth callback did not contain an authorization code');
|
|
165
|
+
if (expectedState && callbackUrl && !state)
|
|
166
|
+
throw new OAuthError('missing_state', 'OAuth callback URL did not contain state');
|
|
167
|
+
if (expectedState && state !== null && state !== expectedState)
|
|
168
|
+
throw new OAuthError('state_mismatch', 'OAuth callback state did not match login session');
|
|
169
|
+
return { code, state: state || undefined };
|
|
170
|
+
}
|
|
171
|
+
export async function exchangeCodeForTokens(params) {
|
|
172
|
+
const body = new URLSearchParams({
|
|
173
|
+
grant_type: 'authorization_code',
|
|
174
|
+
code: params.code,
|
|
175
|
+
redirect_uri: params.redirectUri,
|
|
176
|
+
client_id: params.clientId || DEFAULT_XAI_OAUTH_CLIENT_ID,
|
|
177
|
+
code_verifier: params.verifier,
|
|
178
|
+
});
|
|
179
|
+
if (params.challenge) {
|
|
180
|
+
body.set('code_challenge', params.challenge);
|
|
181
|
+
body.set('code_challenge_method', 'S256');
|
|
182
|
+
}
|
|
183
|
+
const response = await (params.fetchImpl || fetch)(validateXaiHttpsUrl(params.discovery.token_endpoint, 'token_endpoint'), {
|
|
184
|
+
method: 'POST',
|
|
185
|
+
headers: { accept: 'application/json', 'content-type': 'application/x-www-form-urlencoded', 'user-agent': `${PACKAGE_NAME}/${PACKAGE_VERSION}` },
|
|
186
|
+
body,
|
|
187
|
+
});
|
|
188
|
+
const payload = (await response.json().catch(() => ({})));
|
|
189
|
+
if (!response.ok) {
|
|
190
|
+
const message = typeof payload.error_description === 'string' ? payload.error_description : `Token exchange failed with HTTP ${response.status}`;
|
|
191
|
+
throw new OAuthError(response.status === 403 ? 'oauth_entitlement_required' : 'token_exchange_failed', message, response.status);
|
|
192
|
+
}
|
|
193
|
+
if (typeof payload.access_token !== 'string')
|
|
194
|
+
throw new OAuthError('missing_access_token', 'Token exchange response did not contain access_token');
|
|
195
|
+
return {
|
|
196
|
+
access_token: payload.access_token,
|
|
197
|
+
refresh_token: typeof payload.refresh_token === 'string' ? payload.refresh_token : undefined,
|
|
198
|
+
id_token: typeof payload.id_token === 'string' ? payload.id_token : undefined,
|
|
199
|
+
expires_at: tokenExpiresAt(payload),
|
|
200
|
+
token_type: typeof payload.token_type === 'string' ? payload.token_type : 'Bearer',
|
|
201
|
+
scope: typeof payload.scope === 'string' ? payload.scope : undefined,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
export async function persistTokenResponse(params) {
|
|
205
|
+
const state = {
|
|
206
|
+
provider: 'xai-oauth',
|
|
207
|
+
auth_mode: 'oauth_pkce',
|
|
208
|
+
tokens: params.tokens,
|
|
209
|
+
discovery: params.discovery,
|
|
210
|
+
redirect_uri: params.redirectUri,
|
|
211
|
+
base_url: validateInferenceBaseUrl(params.baseUrl || getConfig().oauthBaseUrl),
|
|
212
|
+
last_refresh: new Date().toISOString(),
|
|
213
|
+
};
|
|
214
|
+
await saveOAuthState(state, params.tokenStorePath);
|
|
215
|
+
return state;
|
|
216
|
+
}
|
|
217
|
+
export async function refreshOAuthState(state, options = {}) {
|
|
218
|
+
if (!options.force && !isTokenExpiring(state.tokens))
|
|
219
|
+
return state;
|
|
220
|
+
if (!state.tokens.refresh_token)
|
|
221
|
+
throw new OAuthError('missing_refresh_token', 'OAuth token has no refresh_token; run grok_login again');
|
|
222
|
+
const body = new URLSearchParams({
|
|
223
|
+
grant_type: 'refresh_token',
|
|
224
|
+
client_id: getConfig().oauthClientId || DEFAULT_XAI_OAUTH_CLIENT_ID,
|
|
225
|
+
refresh_token: state.tokens.refresh_token,
|
|
226
|
+
});
|
|
227
|
+
const response = await (options.fetchImpl || fetch)(validateXaiHttpsUrl(state.discovery.token_endpoint, 'token_endpoint'), {
|
|
228
|
+
method: 'POST',
|
|
229
|
+
headers: { accept: 'application/json', 'content-type': 'application/x-www-form-urlencoded', 'user-agent': `${PACKAGE_NAME}/${PACKAGE_VERSION}` },
|
|
230
|
+
body,
|
|
231
|
+
});
|
|
232
|
+
const payload = (await response.json().catch(() => ({})));
|
|
233
|
+
if (!response.ok) {
|
|
234
|
+
const code = response.status === 403 ? 'oauth_entitlement_required' : response.status === 400 || response.status === 401 ? 'invalid_grant' : 'refresh_failed';
|
|
235
|
+
if (code === 'invalid_grant' || code === 'oauth_entitlement_required')
|
|
236
|
+
await markOAuthInvalid(code, options.tokenStorePath);
|
|
237
|
+
throw new OAuthError(code, typeof payload.error_description === 'string' ? payload.error_description : `OAuth refresh failed with HTTP ${response.status}`, response.status);
|
|
238
|
+
}
|
|
239
|
+
if (typeof payload.access_token !== 'string')
|
|
240
|
+
throw new OAuthError('missing_access_token', 'OAuth refresh response did not contain access_token');
|
|
241
|
+
const next = {
|
|
242
|
+
...state,
|
|
243
|
+
invalid: false,
|
|
244
|
+
last_auth_error: undefined,
|
|
245
|
+
last_refresh: new Date().toISOString(),
|
|
246
|
+
tokens: {
|
|
247
|
+
access_token: payload.access_token,
|
|
248
|
+
refresh_token: typeof payload.refresh_token === 'string' ? payload.refresh_token : state.tokens.refresh_token,
|
|
249
|
+
id_token: typeof payload.id_token === 'string' ? payload.id_token : state.tokens.id_token,
|
|
250
|
+
expires_at: tokenExpiresAt(payload),
|
|
251
|
+
token_type: typeof payload.token_type === 'string' ? payload.token_type : 'Bearer',
|
|
252
|
+
scope: typeof payload.scope === 'string' ? payload.scope : state.tokens.scope,
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
await saveOAuthState(next, options.tokenStorePath);
|
|
256
|
+
return next;
|
|
257
|
+
}
|
|
258
|
+
export async function waitForLoopbackCode(session, timeoutMs) {
|
|
259
|
+
const redirect = new URL(session.redirectUri);
|
|
260
|
+
return new Promise((resolve, reject) => {
|
|
261
|
+
const timer = setTimeout(() => {
|
|
262
|
+
server.close();
|
|
263
|
+
reject(new OAuthError('callback_timeout', 'Timed out waiting for OAuth loopback callback'));
|
|
264
|
+
}, timeoutMs);
|
|
265
|
+
const server = http.createServer((req, res) => {
|
|
266
|
+
try {
|
|
267
|
+
const parsed = new URL(req.url || '/', session.redirectUri);
|
|
268
|
+
const { code } = parseCallback(parsed.toString(), session.state);
|
|
269
|
+
res.writeHead(200, { 'content-type': 'text/plain' });
|
|
270
|
+
res.end('Grok login complete. You can close this tab.');
|
|
271
|
+
clearTimeout(timer);
|
|
272
|
+
server.close();
|
|
273
|
+
resolve(code);
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
res.writeHead(400, { 'content-type': 'text/plain' });
|
|
277
|
+
res.end(error.message);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
server.listen(Number(redirect.port), redirect.hostname, () => undefined);
|
|
281
|
+
server.on('error', reject);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/auth/oauth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type CacheResult = {
|
|
2
|
+
path: string;
|
|
3
|
+
bytes: number;
|
|
4
|
+
contentType?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function cacheBase64Artifact(data: string, options?: {
|
|
7
|
+
mediaType: 'image' | 'video';
|
|
8
|
+
contentType?: string;
|
|
9
|
+
cacheDir?: string;
|
|
10
|
+
}): Promise<CacheResult>;
|
|
11
|
+
export declare function cacheUrlArtifact(url: string, options?: {
|
|
12
|
+
mediaType: 'image' | 'video';
|
|
13
|
+
cacheDir?: string;
|
|
14
|
+
maxBytes?: number;
|
|
15
|
+
fetchImpl?: typeof fetch;
|
|
16
|
+
}): Promise<CacheResult>;
|