Skip to content

Commit cbd38d5

Browse files
feat(api): expose authorizationToken as valid auth mechanism
1 parent c25d032 commit cbd38d5

File tree

5 files changed

+76
-26
lines changed

5 files changed

+76
-26
lines changed

.stats.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 107
22
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/mux%2Fmux-ba7ebfd893a1c5d082d55cddaec2ff9219072c9abd96442357aad1748e421483.yml
33
openapi_spec_hash: 94fd98fcb8414d6c70a6ad7593ffcfa4
4-
config_hash: f2bc8e7dd9a1bcf7aa124d84e6172d06
4+
config_hash: 06e26125693367671f74a6d70d1f3333

packages/mcp-server/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
## Installation
44

5+
56
### Via MCP Client
67

78
There is a partial list of existing clients at [modelcontextprotocol.io](https://modelcontextprotocol.io/clients). If you already
@@ -20,7 +21,8 @@ For clients with a configuration JSON, it might look something like this:
2021
"MUX_TOKEN_SECRET": "my secret",
2122
"MUX_WEBHOOK_SECRET": "My Webhook Secret",
2223
"MUX_SIGNING_KEY": "My Jwt Signing Key",
23-
"MUX_PRIVATE_KEY": "My Jwt Private Key"
24+
"MUX_PRIVATE_KEY": "My Jwt Private Key",
25+
"MUX_AUTHORIZATION_TOKEN": "my authorization token"
2426
}
2527
}
2628
}

packages/mcp-server/cloudflare-worker/src/index.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,17 @@ const serverConfig: ServerConfig = {
2020
key: 'tokenId',
2121
label: 'Token ID',
2222
description: '',
23-
required: true,
24-
default: undefined,
23+
required: false,
24+
default: null,
2525
placeholder: 'my token id',
2626
type: 'password',
2727
},
2828
{
2929
key: 'tokenSecret',
3030
label: 'Token Secret',
3131
description: '',
32-
required: true,
33-
default: undefined,
32+
required: false,
33+
default: null,
3434
placeholder: 'my secret',
3535
type: 'password',
3636
},
@@ -61,6 +61,15 @@ const serverConfig: ServerConfig = {
6161
placeholder: 'My Jwt Private Key',
6262
type: 'string',
6363
},
64+
{
65+
key: 'authorizationToken',
66+
label: 'Authorization Token',
67+
description: '',
68+
required: false,
69+
default: null,
70+
placeholder: 'my authorization token',
71+
type: 'password',
72+
},
6473
],
6574
};
6675

packages/mcp-server/src/headers.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export const parseAuthHeaders = (req: IncomingMessage): Partial<ClientOptions> =
1515
tokenId: rawValue.slice(0, rawValue.search(':')),
1616
tokenSecret: rawValue.slice(rawValue.search(':') + 1),
1717
};
18+
case 'Bearer':
19+
return { authorizationToken: req.headers.authorization.slice('Bearer '.length) };
1820
default:
1921
throw new Error(`Unsupported authorization scheme`);
2022
}
@@ -28,5 +30,9 @@ export const parseAuthHeaders = (req: IncomingMessage): Partial<ClientOptions> =
2830
req.headers['x-mux-token-secret'] instanceof Array ?
2931
req.headers['x-mux-token-secret'][0]
3032
: req.headers['x-mux-token-secret'];
31-
return { tokenId, tokenSecret };
33+
const authorizationToken =
34+
req.headers['x-mux-authorization-token'] instanceof Array ?
35+
req.headers['x-mux-authorization-token'][0]
36+
: req.headers['x-mux-authorization-token'];
37+
return { tokenId, tokenSecret, authorizationToken };
3238
};

src/index.ts

Lines changed: 52 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ export interface ClientOptions {
2222
/**
2323
* Defaults to process.env['MUX_TOKEN_ID'].
2424
*/
25-
tokenId?: string | undefined;
25+
tokenId?: string | null | undefined;
2626

2727
/**
2828
* Defaults to process.env['MUX_TOKEN_SECRET'].
2929
*/
30-
tokenSecret?: string | undefined;
30+
tokenSecret?: string | null | undefined;
3131

3232
/**
3333
* Defaults to process.env['MUX_WEBHOOK_SECRET'].
@@ -44,6 +44,11 @@ export interface ClientOptions {
4444
*/
4545
jwtPrivateKey?: string | null | undefined;
4646

47+
/**
48+
* Defaults to process.env['MUX_AUTHORIZATION_TOKEN'].
49+
*/
50+
authorizationToken?: string | null | undefined;
51+
4752
/**
4853
* Override the default base URL for the API, e.g., "https://api.example.com/v2/"
4954
*
@@ -107,22 +112,24 @@ export interface ClientOptions {
107112
* API Client for interfacing with the Mux API.
108113
*/
109114
export class Mux extends Core.APIClient {
110-
tokenId: string;
111-
tokenSecret: string;
115+
tokenId: string | null;
116+
tokenSecret: string | null;
112117
webhookSecret: string | null;
113118
jwtSigningKey: string | null;
114119
jwtPrivateKey: string | null;
120+
authorizationToken: string | null;
115121

116122
private _options: ClientOptions;
117123

118124
/**
119125
* API Client for interfacing with the Mux API.
120126
*
121-
* @param {string | undefined} [opts.tokenId=process.env['MUX_TOKEN_ID'] ?? undefined]
122-
* @param {string | undefined} [opts.tokenSecret=process.env['MUX_TOKEN_SECRET'] ?? undefined]
127+
* @param {string | null | undefined} [opts.tokenId=process.env['MUX_TOKEN_ID'] ?? null]
128+
* @param {string | null | undefined} [opts.tokenSecret=process.env['MUX_TOKEN_SECRET'] ?? null]
123129
* @param {string | null | undefined} [opts.webhookSecret=process.env['MUX_WEBHOOK_SECRET'] ?? null]
124130
* @param {string | null | undefined} [opts.jwtSigningKey=process.env['MUX_SIGNING_KEY'] ?? null]
125131
* @param {string | null | undefined} [opts.jwtPrivateKey=process.env['MUX_PRIVATE_KEY'] ?? null]
132+
* @param {string | null | undefined} [opts.authorizationToken=process.env['MUX_AUTHORIZATION_TOKEN'] ?? null]
126133
* @param {string} [opts.baseURL=process.env['MUX_BASE_URL'] ?? https://api.mux.com] - Override the default base URL for the API.
127134
* @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out.
128135
* @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections.
@@ -133,30 +140,21 @@ export class Mux extends Core.APIClient {
133140
*/
134141
constructor({
135142
baseURL = Core.readEnv('MUX_BASE_URL'),
136-
tokenId = Core.readEnv('MUX_TOKEN_ID'),
137-
tokenSecret = Core.readEnv('MUX_TOKEN_SECRET'),
143+
tokenId = Core.readEnv('MUX_TOKEN_ID') ?? null,
144+
tokenSecret = Core.readEnv('MUX_TOKEN_SECRET') ?? null,
138145
webhookSecret = Core.readEnv('MUX_WEBHOOK_SECRET') ?? null,
139146
jwtSigningKey = Core.readEnv('MUX_SIGNING_KEY') ?? null,
140147
jwtPrivateKey = Core.readEnv('MUX_PRIVATE_KEY') ?? null,
148+
authorizationToken = Core.readEnv('MUX_AUTHORIZATION_TOKEN') ?? null,
141149
...opts
142150
}: ClientOptions = {}) {
143-
if (tokenId === undefined) {
144-
throw new Errors.MuxError(
145-
"The MUX_TOKEN_ID environment variable is missing or empty; either provide it, or instantiate the Mux client with an tokenId option, like new Mux({ tokenId: 'my token id' }).",
146-
);
147-
}
148-
if (tokenSecret === undefined) {
149-
throw new Errors.MuxError(
150-
"The MUX_TOKEN_SECRET environment variable is missing or empty; either provide it, or instantiate the Mux client with an tokenSecret option, like new Mux({ tokenSecret: 'my secret' }).",
151-
);
152-
}
153-
154151
const options: ClientOptions = {
155152
tokenId,
156153
tokenSecret,
157154
webhookSecret,
158155
jwtSigningKey,
159156
jwtPrivateKey,
157+
authorizationToken,
160158
...opts,
161159
baseURL: baseURL || `https://api.mux.com`,
162160
};
@@ -177,6 +175,7 @@ export class Mux extends Core.APIClient {
177175
this.webhookSecret = webhookSecret;
178176
this.jwtSigningKey = jwtSigningKey;
179177
this.jwtPrivateKey = jwtPrivateKey;
178+
this.authorizationToken = authorizationToken;
180179
}
181180

182181
video: API.Video = new API.Video(this);
@@ -203,7 +202,34 @@ export class Mux extends Core.APIClient {
203202
};
204203
}
205204

205+
protected override validateHeaders(headers: Core.Headers, customHeaders: Core.Headers) {
206+
if (this.tokenId && this.tokenSecret && headers['authorization']) {
207+
return;
208+
}
209+
if (customHeaders['authorization'] === null) {
210+
return;
211+
}
212+
213+
if (this.authorizationToken && headers['authorization']) {
214+
return;
215+
}
216+
if (customHeaders['authorization'] === null) {
217+
return;
218+
}
219+
220+
throw new Error(
221+
'Could not resolve authentication method. Expected either tokenId, tokenSecret or authorizationToken to be set. Or for one of the "Authorization" or "Authorization" headers to be explicitly omitted',
222+
);
223+
}
224+
206225
protected override authHeaders(opts: Core.FinalRequestOptions): Core.Headers {
226+
return {
227+
...this.accessTokenAuth(opts),
228+
...this.authorizationTokenAuth(opts),
229+
};
230+
}
231+
232+
protected accessTokenAuth(opts: Core.FinalRequestOptions): Core.Headers {
207233
if (!this.tokenId) {
208234
return {};
209235
}
@@ -217,6 +243,13 @@ export class Mux extends Core.APIClient {
217243
return { Authorization };
218244
}
219245

246+
protected authorizationTokenAuth(opts: Core.FinalRequestOptions): Core.Headers {
247+
if (this.authorizationToken == null) {
248+
return {};
249+
}
250+
return { Authorization: `Bearer ${this.authorizationToken}` };
251+
}
252+
220253
protected override stringifyQuery(query: Record<string, unknown>): string {
221254
return qs.stringify(query, { arrayFormat: 'brackets' });
222255
}

0 commit comments

Comments
 (0)