Merge main into proxy branch (formatting and docs)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Gregory Schier
2026-03-13 12:09:59 -07:00
parent 3c4035097a
commit 7314aedc71
712 changed files with 13408 additions and 13322 deletions

View File

@@ -4,13 +4,13 @@ import type {
GetHttpAuthenticationConfigRequest,
JsonPrimitive,
PluginDefinition,
} from '@yaakapp/api';
import type { Algorithm } from 'jsonwebtoken';
} from "@yaakapp/api";
import type { Algorithm } from "jsonwebtoken";
import {
buildHostedCallbackRedirectUri,
DEFAULT_LOCALHOST_PORT,
stopActiveServer,
} from './callbackServer';
} from "./callbackServer";
import {
type CallbackType,
DEFAULT_PKCE_METHOD,
@@ -18,31 +18,31 @@ import {
getAuthorizationCode,
PKCE_PLAIN,
PKCE_SHA256,
} from './grants/authorizationCode';
} from "./grants/authorizationCode";
import {
defaultJwtAlgorithm,
getClientCredentials,
jwtAlgorithms,
} from './grants/clientCredentials';
import { getImplicit } from './grants/implicit';
import { getPassword } from './grants/password';
import type { AccessToken, TokenStoreArgs } from './store';
import { deleteToken, getToken, resetDataDirKey } from './store';
} from "./grants/clientCredentials";
import { getImplicit } from "./grants/implicit";
import { getPassword } from "./grants/password";
import type { AccessToken, TokenStoreArgs } from "./store";
import { deleteToken, getToken, resetDataDirKey } from "./store";
type GrantType = 'authorization_code' | 'implicit' | 'password' | 'client_credentials';
type GrantType = "authorization_code" | "implicit" | "password" | "client_credentials";
const grantTypes: FormInputSelectOption[] = [
{ label: 'Authorization Code', value: 'authorization_code' },
{ label: 'Implicit', value: 'implicit' },
{ label: 'Resource Owner Password Credential', value: 'password' },
{ label: 'Client Credentials', value: 'client_credentials' },
{ label: "Authorization Code", value: "authorization_code" },
{ label: "Implicit", value: "implicit" },
{ label: "Resource Owner Password Credential", value: "password" },
{ label: "Client Credentials", value: "client_credentials" },
];
const defaultGrantType = grantTypes[0]?.value;
function hiddenIfNot(
grantTypes: GrantType[],
...other: ((values: GetHttpAuthenticationConfigRequest['values']) => boolean)[]
...other: ((values: GetHttpAuthenticationConfigRequest["values"]) => boolean)[]
) {
return (_ctx: Context, { values }: GetHttpAuthenticationConfigRequest) => {
const hasGrantType = grantTypes.find((t) => t === String(values.grantType ?? defaultGrantType));
@@ -53,37 +53,37 @@ function hiddenIfNot(
}
const authorizationUrls = [
'https://github.com/login/oauth/authorize',
'https://account.box.com/api/oauth2/authorize',
'https://accounts.google.com/o/oauth2/v2/auth',
'https://api.imgur.com/oauth2/authorize',
'https://bitly.com/oauth/authorize',
'https://gitlab.example.com/oauth/authorize',
'https://medium.com/m/oauth/authorize',
'https://public-api.wordpress.com/oauth2/authorize',
'https://slack.com/oauth/authorize',
'https://todoist.com/oauth/authorize',
'https://www.dropbox.com/oauth2/authorize',
'https://www.linkedin.com/oauth/v2/authorization',
'https://MY_SHOP.myshopify.com/admin/oauth/access_token',
'https://appcenter.intuit.com/app/connect/oauth2/authorize',
"https://github.com/login/oauth/authorize",
"https://account.box.com/api/oauth2/authorize",
"https://accounts.google.com/o/oauth2/v2/auth",
"https://api.imgur.com/oauth2/authorize",
"https://bitly.com/oauth/authorize",
"https://gitlab.example.com/oauth/authorize",
"https://medium.com/m/oauth/authorize",
"https://public-api.wordpress.com/oauth2/authorize",
"https://slack.com/oauth/authorize",
"https://todoist.com/oauth/authorize",
"https://www.dropbox.com/oauth2/authorize",
"https://www.linkedin.com/oauth/v2/authorization",
"https://MY_SHOP.myshopify.com/admin/oauth/access_token",
"https://appcenter.intuit.com/app/connect/oauth2/authorize",
];
const accessTokenUrls = [
'https://github.com/login/oauth/access_token',
'https://api-ssl.bitly.com/oauth/access_token',
'https://api.box.com/oauth2/token',
'https://api.dropboxapi.com/oauth2/token',
'https://api.imgur.com/oauth2/token',
'https://api.medium.com/v1/tokens',
'https://gitlab.example.com/oauth/token',
'https://public-api.wordpress.com/oauth2/token',
'https://slack.com/api/oauth.access',
'https://todoist.com/oauth/access_token',
'https://www.googleapis.com/oauth2/v4/token',
'https://www.linkedin.com/oauth/v2/accessToken',
'https://MY_SHOP.myshopify.com/admin/oauth/authorize',
'https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer',
"https://github.com/login/oauth/access_token",
"https://api-ssl.bitly.com/oauth/access_token",
"https://api.box.com/oauth2/token",
"https://api.dropboxapi.com/oauth2/token",
"https://api.imgur.com/oauth2/token",
"https://api.medium.com/v1/tokens",
"https://gitlab.example.com/oauth/token",
"https://public-api.wordpress.com/oauth2/token",
"https://slack.com/api/oauth.access",
"https://todoist.com/oauth/access_token",
"https://www.googleapis.com/oauth2/v4/token",
"https://www.linkedin.com/oauth/v2/accessToken",
"https://MY_SHOP.myshopify.com/admin/oauth/authorize",
"https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
];
export const plugin: PluginDefinition = {
@@ -91,59 +91,59 @@ export const plugin: PluginDefinition = {
stopActiveServer();
},
authentication: {
name: 'oauth2',
label: 'OAuth 2.0',
shortLabel: 'OAuth 2',
name: "oauth2",
label: "OAuth 2.0",
shortLabel: "OAuth 2",
actions: [
{
label: 'Copy Current Token',
label: "Copy Current Token",
async onSelect(ctx, { contextId, values }) {
const tokenArgs: TokenStoreArgs = {
contextId,
authorizationUrl: stringArg(values, 'authorizationUrl'),
accessTokenUrl: stringArg(values, 'accessTokenUrl'),
clientId: stringArg(values, 'clientId'),
authorizationUrl: stringArg(values, "authorizationUrl"),
accessTokenUrl: stringArg(values, "accessTokenUrl"),
clientId: stringArg(values, "clientId"),
};
const token = await getToken(ctx, tokenArgs);
if (token == null) {
await ctx.toast.show({
message: 'No token to copy',
color: 'warning',
message: "No token to copy",
color: "warning",
});
} else {
await ctx.clipboard.copyText(token.response.access_token);
await ctx.toast.show({
message: 'Token copied to clipboard',
icon: 'copy',
color: 'success',
message: "Token copied to clipboard",
icon: "copy",
color: "success",
});
}
},
},
{
label: 'Delete Token',
label: "Delete Token",
async onSelect(ctx, { contextId, values }) {
const tokenArgs: TokenStoreArgs = {
contextId,
authorizationUrl: stringArg(values, 'authorizationUrl'),
accessTokenUrl: stringArg(values, 'accessTokenUrl'),
clientId: stringArg(values, 'clientId'),
authorizationUrl: stringArg(values, "authorizationUrl"),
accessTokenUrl: stringArg(values, "accessTokenUrl"),
clientId: stringArg(values, "clientId"),
};
if (await deleteToken(ctx, tokenArgs)) {
await ctx.toast.show({
message: 'Token deleted',
color: 'success',
message: "Token deleted",
color: "success",
});
} else {
await ctx.toast.show({
message: 'No token to delete',
color: 'warning',
message: "No token to delete",
color: "warning",
});
}
},
},
{
label: 'Clear Window Session',
label: "Clear Window Session",
async onSelect(ctx, { contextId }) {
await resetDataDirKey(ctx, contextId);
},
@@ -151,85 +151,85 @@ export const plugin: PluginDefinition = {
],
args: [
{
type: 'select',
name: 'grantType',
label: 'Grant Type',
type: "select",
name: "grantType",
label: "Grant Type",
defaultValue: defaultGrantType,
options: grantTypes,
},
{
type: 'select',
name: 'clientCredentialsMethod',
label: 'Authentication Method',
type: "select",
name: "clientCredentialsMethod",
label: "Authentication Method",
description:
'"Client Secret" sends client_secret. \n' + '"Client Assertion" sends a signed JWT.',
defaultValue: 'client_secret',
defaultValue: "client_secret",
options: [
{ label: 'Client Secret', value: 'client_secret' },
{ label: 'Client Assertion', value: 'client_assertion' },
{ label: "Client Secret", value: "client_secret" },
{ label: "Client Assertion", value: "client_assertion" },
],
dynamic: hiddenIfNot(['client_credentials']),
dynamic: hiddenIfNot(["client_credentials"]),
},
{
type: 'text',
name: 'clientId',
label: 'Client ID',
type: "text",
name: "clientId",
label: "Client ID",
optional: true,
},
{
type: 'text',
name: 'clientSecret',
label: 'Client Secret',
type: "text",
name: "clientSecret",
label: "Client Secret",
optional: true,
password: true,
dynamic: hiddenIfNot(
['authorization_code', 'password', 'client_credentials'],
(values) => values.clientCredentialsMethod === 'client_secret',
["authorization_code", "password", "client_credentials"],
(values) => values.clientCredentialsMethod === "client_secret",
),
},
{
type: 'select',
name: 'clientAssertionAlgorithm',
label: 'JWT Algorithm',
type: "select",
name: "clientAssertionAlgorithm",
label: "JWT Algorithm",
defaultValue: defaultJwtAlgorithm,
options: jwtAlgorithms.map((value) => ({
label: value === 'none' ? 'None' : value,
label: value === "none" ? "None" : value,
value,
})),
dynamic: hiddenIfNot(
['client_credentials'],
({ clientCredentialsMethod }) => clientCredentialsMethod === 'client_assertion',
["client_credentials"],
({ clientCredentialsMethod }) => clientCredentialsMethod === "client_assertion",
),
},
{
type: 'text',
name: 'clientAssertionSecret',
label: 'JWT Secret',
type: "text",
name: "clientAssertionSecret",
label: "JWT Secret",
description:
'Can be HMAC, PEM or JWK. Make sure you pick the correct algorithm type above.',
"Can be HMAC, PEM or JWK. Make sure you pick the correct algorithm type above.",
password: true,
optional: true,
multiLine: true,
dynamic: hiddenIfNot(
['client_credentials'],
({ clientCredentialsMethod }) => clientCredentialsMethod === 'client_assertion',
["client_credentials"],
({ clientCredentialsMethod }) => clientCredentialsMethod === "client_assertion",
),
},
{
type: 'checkbox',
name: 'clientAssertionSecretBase64',
label: 'JWT secret is base64 encoded',
type: "checkbox",
name: "clientAssertionSecretBase64",
label: "JWT secret is base64 encoded",
dynamic: hiddenIfNot(
['client_credentials'],
({ clientCredentialsMethod }) => clientCredentialsMethod === 'client_assertion',
["client_credentials"],
({ clientCredentialsMethod }) => clientCredentialsMethod === "client_assertion",
),
},
{
type: 'text',
name: 'authorizationUrl',
type: "text",
name: "authorizationUrl",
optional: true,
label: 'Authorization URL',
dynamic: hiddenIfNot(['authorization_code', 'implicit']),
label: "Authorization URL",
dynamic: hiddenIfNot(["authorization_code", "implicit"]),
placeholder: authorizationUrls[0],
completionOptions: authorizationUrls.map((url) => ({
label: url,
@@ -237,103 +237,103 @@ export const plugin: PluginDefinition = {
})),
},
{
type: 'text',
name: 'accessTokenUrl',
type: "text",
name: "accessTokenUrl",
optional: true,
label: 'Access Token URL',
label: "Access Token URL",
placeholder: accessTokenUrls[0],
dynamic: hiddenIfNot(['authorization_code', 'password', 'client_credentials']),
dynamic: hiddenIfNot(["authorization_code", "password", "client_credentials"]),
completionOptions: accessTokenUrls.map((url) => ({
label: url,
value: url,
})),
},
{
type: 'banner',
type: "banner",
inputs: [
{
type: 'checkbox',
name: 'useExternalBrowser',
label: 'Use External Browser',
type: "checkbox",
name: "useExternalBrowser",
label: "Use External Browser",
description:
'Open authorization URL in your system browser instead of the embedded browser. ' +
'Useful when the OAuth provider blocks embedded browsers or you need existing browser sessions.',
dynamic: hiddenIfNot(['authorization_code', 'implicit']),
"Open authorization URL in your system browser instead of the embedded browser. " +
"Useful when the OAuth provider blocks embedded browsers or you need existing browser sessions.",
dynamic: hiddenIfNot(["authorization_code", "implicit"]),
},
{
type: 'text',
name: 'redirectUri',
label: 'Redirect URI (can be any valid URL)',
placeholder: 'https://mysite.example.com/oauth/callback',
type: "text",
name: "redirectUri",
label: "Redirect URI (can be any valid URL)",
placeholder: "https://mysite.example.com/oauth/callback",
description:
'URI the OAuth provider redirects to after authorization. Yaak intercepts this automatically in its embedded browser so any valid URI will work.',
"URI the OAuth provider redirects to after authorization. Yaak intercepts this automatically in its embedded browser so any valid URI will work.",
optional: true,
dynamic: hiddenIfNot(
['authorization_code', 'implicit'],
["authorization_code", "implicit"],
({ useExternalBrowser }) => !useExternalBrowser,
),
},
{
type: 'h_stack',
type: "h_stack",
inputs: [
{
type: 'select',
name: 'callbackType',
label: 'Callback Type',
type: "select",
name: "callbackType",
label: "Callback Type",
description:
'"Hosted Redirect" uses an external Yaak-hosted endpoint. "Localhost" starts a local server to receive the callback.',
defaultValue: 'hosted',
defaultValue: "hosted",
options: [
{ label: 'Hosted Redirect', value: 'hosted' },
{ label: 'Localhost', value: 'localhost' },
{ label: "Hosted Redirect", value: "hosted" },
{ label: "Localhost", value: "localhost" },
],
dynamic: hiddenIfNot(
['authorization_code', 'implicit'],
["authorization_code", "implicit"],
({ useExternalBrowser }) => !!useExternalBrowser,
),
},
{
type: 'text',
name: 'callbackPort',
label: 'Callback Port',
type: "text",
name: "callbackPort",
label: "Callback Port",
placeholder: `${DEFAULT_LOCALHOST_PORT}`,
description:
'Port for the local callback server. Defaults to ' +
"Port for the local callback server. Defaults to " +
DEFAULT_LOCALHOST_PORT +
' if empty.',
" if empty.",
optional: true,
dynamic: hiddenIfNot(
['authorization_code', 'implicit'],
["authorization_code", "implicit"],
({ useExternalBrowser }) => !!useExternalBrowser,
),
},
],
},
{
type: 'banner',
color: 'info',
type: "banner",
color: "info",
inputs: [
{
type: 'markdown',
content: 'Redirect URI to Register',
type: "markdown",
content: "Redirect URI to Register",
async dynamic(_ctx, { values }) {
const grantType = String(values.grantType ?? defaultGrantType);
const useExternalBrowser = !!values.useExternalBrowser;
const callbackType = (stringArg(values, 'callbackType') ||
'localhost') as CallbackType;
const callbackType = (stringArg(values, "callbackType") ||
"localhost") as CallbackType;
// Only show for authorization_code and implicit with external browser enabled
if (
!['authorization_code', 'implicit'].includes(grantType) ||
!["authorization_code", "implicit"].includes(grantType) ||
!useExternalBrowser
) {
return { hidden: true };
}
// Compute the redirect URI based on callback type
const port = intArg(values, 'callbackPort') || DEFAULT_LOCALHOST_PORT;
const port = intArg(values, "callbackPort") || DEFAULT_LOCALHOST_PORT;
let redirectUri: string;
if (callbackType === 'hosted') {
if (callbackType === "hosted") {
redirectUri = buildHostedCallbackRedirectUri(port);
} else {
redirectUri = `http://127.0.0.1:${port}/callback`;
@@ -350,149 +350,149 @@ export const plugin: PluginDefinition = {
],
},
{
type: 'text',
name: 'state',
label: 'State',
type: "text",
name: "state",
label: "State",
optional: true,
dynamic: hiddenIfNot(['authorization_code', 'implicit']),
dynamic: hiddenIfNot(["authorization_code", "implicit"]),
},
{ type: 'text', name: 'scope', label: 'Scope', optional: true },
{ type: 'text', name: 'audience', label: 'Audience', optional: true },
{ type: "text", name: "scope", label: "Scope", optional: true },
{ type: "text", name: "audience", label: "Audience", optional: true },
{
type: 'select',
name: 'tokenName',
label: 'Token for authorization',
type: "select",
name: "tokenName",
label: "Token for authorization",
description:
'Select which token to send in the "Authorization: Bearer" header. Most APIs expect ' +
'access_token, but some (like OpenID Connect) require id_token.',
defaultValue: 'access_token',
"access_token, but some (like OpenID Connect) require id_token.",
defaultValue: "access_token",
options: [
{ label: 'access_token', value: 'access_token' },
{ label: 'id_token', value: 'id_token' },
{ label: "access_token", value: "access_token" },
{ label: "id_token", value: "id_token" },
],
dynamic: hiddenIfNot(['authorization_code', 'implicit']),
dynamic: hiddenIfNot(["authorization_code", "implicit"]),
},
{
type: 'banner',
type: "banner",
inputs: [
{
type: 'checkbox',
name: 'usePkce',
label: 'Use PKCE',
dynamic: hiddenIfNot(['authorization_code']),
type: "checkbox",
name: "usePkce",
label: "Use PKCE",
dynamic: hiddenIfNot(["authorization_code"]),
},
{
type: 'select',
name: 'pkceChallengeMethod',
label: 'Code Challenge Method',
type: "select",
name: "pkceChallengeMethod",
label: "Code Challenge Method",
options: [
{ label: 'SHA-256', value: PKCE_SHA256 },
{ label: 'Plain', value: PKCE_PLAIN },
{ label: "SHA-256", value: PKCE_SHA256 },
{ label: "Plain", value: PKCE_PLAIN },
],
defaultValue: DEFAULT_PKCE_METHOD,
dynamic: hiddenIfNot(['authorization_code'], ({ usePkce }) => !!usePkce),
dynamic: hiddenIfNot(["authorization_code"], ({ usePkce }) => !!usePkce),
},
{
type: 'text',
name: 'pkceCodeChallenge',
label: 'Code Verifier',
placeholder: 'Automatically generated when not set',
type: "text",
name: "pkceCodeChallenge",
label: "Code Verifier",
placeholder: "Automatically generated when not set",
optional: true,
dynamic: hiddenIfNot(['authorization_code'], ({ usePkce }) => !!usePkce),
dynamic: hiddenIfNot(["authorization_code"], ({ usePkce }) => !!usePkce),
},
],
},
{
type: 'h_stack',
type: "h_stack",
inputs: [
{
type: 'text',
name: 'username',
label: 'Username',
type: "text",
name: "username",
label: "Username",
optional: true,
dynamic: hiddenIfNot(['password']),
dynamic: hiddenIfNot(["password"]),
},
{
type: 'text',
name: 'password',
label: 'Password',
type: "text",
name: "password",
label: "Password",
password: true,
optional: true,
dynamic: hiddenIfNot(['password']),
dynamic: hiddenIfNot(["password"]),
},
],
},
{
type: 'select',
name: 'responseType',
label: 'Response Type',
defaultValue: 'token',
type: "select",
name: "responseType",
label: "Response Type",
defaultValue: "token",
options: [
{ label: 'Access Token', value: 'token' },
{ label: 'ID Token', value: 'id_token' },
{ label: 'ID and Access Token', value: 'id_token token' },
{ label: "Access Token", value: "token" },
{ label: "ID Token", value: "id_token" },
{ label: "ID and Access Token", value: "id_token token" },
],
dynamic: hiddenIfNot(['implicit']),
dynamic: hiddenIfNot(["implicit"]),
},
{
type: 'accordion',
label: 'Advanced',
type: "accordion",
label: "Advanced",
inputs: [
{
type: 'text',
name: 'headerName',
label: 'Header Name',
defaultValue: 'Authorization',
type: "text",
name: "headerName",
label: "Header Name",
defaultValue: "Authorization",
},
{
type: 'text',
name: 'headerPrefix',
label: 'Header Prefix',
type: "text",
name: "headerPrefix",
label: "Header Prefix",
optional: true,
defaultValue: 'Bearer',
defaultValue: "Bearer",
},
{
type: 'select',
name: 'credentials',
label: 'Send Credentials',
defaultValue: 'body',
type: "select",
name: "credentials",
label: "Send Credentials",
defaultValue: "body",
options: [
{ label: 'In Request Body', value: 'body' },
{ label: 'As Basic Authentication', value: 'basic' },
{ label: "In Request Body", value: "body" },
{ label: "As Basic Authentication", value: "basic" },
],
dynamic: (_ctx: Context, { values }: GetHttpAuthenticationConfigRequest) => ({
hidden:
values.grantType === 'client_credentials' &&
values.clientCredentialsMethod === 'client_assertion',
values.grantType === "client_credentials" &&
values.clientCredentialsMethod === "client_assertion",
}),
},
],
},
{
type: 'accordion',
label: 'Access Token Response',
type: "accordion",
label: "Access Token Response",
inputs: [],
async dynamic(ctx, { contextId, values }) {
const tokenArgs: TokenStoreArgs = {
contextId,
authorizationUrl: stringArg(values, 'authorizationUrl'),
accessTokenUrl: stringArg(values, 'accessTokenUrl'),
clientId: stringArg(values, 'clientId'),
authorizationUrl: stringArg(values, "authorizationUrl"),
accessTokenUrl: stringArg(values, "accessTokenUrl"),
clientId: stringArg(values, "clientId"),
};
const token = await getToken(ctx, tokenArgs);
if (token == null) {
return { hidden: true };
}
return {
label: 'Access Token Response',
label: "Access Token Response",
inputs: [
{
type: 'editor',
name: 'response',
type: "editor",
name: "response",
defaultValue: JSON.stringify(token.response, null, 2),
hideLabel: true,
readOnly: true,
language: 'json',
language: "json",
},
],
};
@@ -500,101 +500,101 @@ export const plugin: PluginDefinition = {
},
],
async onApply(ctx, { values, contextId }) {
const headerPrefix = stringArg(values, 'headerPrefix');
const grantType = stringArg(values, 'grantType') as GrantType;
const credentialsInBody = values.credentials === 'body';
const tokenName = values.tokenName === 'id_token' ? 'id_token' : 'access_token';
const headerPrefix = stringArg(values, "headerPrefix");
const grantType = stringArg(values, "grantType") as GrantType;
const credentialsInBody = values.credentials === "body";
const tokenName = values.tokenName === "id_token" ? "id_token" : "access_token";
// Build external browser options if enabled
const useExternalBrowser = !!values.useExternalBrowser;
const externalBrowserOptions = useExternalBrowser
? {
useExternalBrowser: true,
callbackType: (stringArg(values, 'callbackType') || 'localhost') as CallbackType,
callbackPort: intArg(values, 'callbackPort') ?? undefined,
callbackType: (stringArg(values, "callbackType") || "localhost") as CallbackType,
callbackPort: intArg(values, "callbackPort") ?? undefined,
}
: undefined;
let token: AccessToken;
if (grantType === 'authorization_code') {
const authorizationUrl = stringArg(values, 'authorizationUrl');
const accessTokenUrl = stringArg(values, 'accessTokenUrl');
if (grantType === "authorization_code") {
const authorizationUrl = stringArg(values, "authorizationUrl");
const accessTokenUrl = stringArg(values, "accessTokenUrl");
token = await getAuthorizationCode(ctx, contextId, {
accessTokenUrl:
accessTokenUrl === '' || accessTokenUrl.match(/^https?:\/\//)
accessTokenUrl === "" || accessTokenUrl.match(/^https?:\/\//)
? accessTokenUrl
: `https://${accessTokenUrl}`,
authorizationUrl:
authorizationUrl === '' || authorizationUrl.match(/^https?:\/\//)
authorizationUrl === "" || authorizationUrl.match(/^https?:\/\//)
? authorizationUrl
: `https://${authorizationUrl}`,
clientId: stringArg(values, 'clientId'),
clientSecret: stringArg(values, 'clientSecret'),
redirectUri: stringArgOrNull(values, 'redirectUri'),
scope: stringArgOrNull(values, 'scope'),
audience: stringArgOrNull(values, 'audience'),
state: stringArgOrNull(values, 'state'),
clientId: stringArg(values, "clientId"),
clientSecret: stringArg(values, "clientSecret"),
redirectUri: stringArgOrNull(values, "redirectUri"),
scope: stringArgOrNull(values, "scope"),
audience: stringArgOrNull(values, "audience"),
state: stringArgOrNull(values, "state"),
credentialsInBody,
pkce: values.usePkce
? {
challengeMethod: stringArg(values, 'pkceChallengeMethod') || DEFAULT_PKCE_METHOD,
codeVerifier: stringArg(values, 'pkceCodeVerifier') || genPkceCodeVerifier(),
challengeMethod: stringArg(values, "pkceChallengeMethod") || DEFAULT_PKCE_METHOD,
codeVerifier: stringArg(values, "pkceCodeVerifier") || genPkceCodeVerifier(),
}
: null,
tokenName: tokenName,
externalBrowser: externalBrowserOptions,
});
} else if (grantType === 'implicit') {
const authorizationUrl = stringArg(values, 'authorizationUrl');
} else if (grantType === "implicit") {
const authorizationUrl = stringArg(values, "authorizationUrl");
token = await getImplicit(ctx, contextId, {
authorizationUrl: authorizationUrl.match(/^https?:\/\//)
? authorizationUrl
: `https://${authorizationUrl}`,
clientId: stringArg(values, 'clientId'),
redirectUri: stringArgOrNull(values, 'redirectUri'),
responseType: stringArg(values, 'responseType'),
scope: stringArgOrNull(values, 'scope'),
audience: stringArgOrNull(values, 'audience'),
state: stringArgOrNull(values, 'state'),
clientId: stringArg(values, "clientId"),
redirectUri: stringArgOrNull(values, "redirectUri"),
responseType: stringArg(values, "responseType"),
scope: stringArgOrNull(values, "scope"),
audience: stringArgOrNull(values, "audience"),
state: stringArgOrNull(values, "state"),
tokenName: tokenName,
externalBrowser: externalBrowserOptions,
});
} else if (grantType === 'client_credentials') {
const accessTokenUrl = stringArg(values, 'accessTokenUrl');
} else if (grantType === "client_credentials") {
const accessTokenUrl = stringArg(values, "accessTokenUrl");
token = await getClientCredentials(ctx, contextId, {
accessTokenUrl: accessTokenUrl.match(/^https?:\/\//)
? accessTokenUrl
: `https://${accessTokenUrl}`,
clientId: stringArg(values, 'clientId'),
clientAssertionAlgorithm: stringArg(values, 'clientAssertionAlgorithm') as Algorithm,
clientSecret: stringArg(values, 'clientSecret'),
clientCredentialsMethod: stringArg(values, 'clientCredentialsMethod'),
clientAssertionSecret: stringArg(values, 'clientAssertionSecret'),
clientId: stringArg(values, "clientId"),
clientAssertionAlgorithm: stringArg(values, "clientAssertionAlgorithm") as Algorithm,
clientSecret: stringArg(values, "clientSecret"),
clientCredentialsMethod: stringArg(values, "clientCredentialsMethod"),
clientAssertionSecret: stringArg(values, "clientAssertionSecret"),
clientAssertionSecretBase64: !!values.clientAssertionSecretBase64,
scope: stringArgOrNull(values, 'scope'),
audience: stringArgOrNull(values, 'audience'),
scope: stringArgOrNull(values, "scope"),
audience: stringArgOrNull(values, "audience"),
credentialsInBody,
});
} else if (grantType === 'password') {
const accessTokenUrl = stringArg(values, 'accessTokenUrl');
} else if (grantType === "password") {
const accessTokenUrl = stringArg(values, "accessTokenUrl");
token = await getPassword(ctx, contextId, {
accessTokenUrl: accessTokenUrl.match(/^https?:\/\//)
? accessTokenUrl
: `https://${accessTokenUrl}`,
clientId: stringArg(values, 'clientId'),
clientSecret: stringArg(values, 'clientSecret'),
username: stringArg(values, 'username'),
password: stringArg(values, 'password'),
scope: stringArgOrNull(values, 'scope'),
audience: stringArgOrNull(values, 'audience'),
clientId: stringArg(values, "clientId"),
clientSecret: stringArg(values, "clientSecret"),
username: stringArg(values, "username"),
password: stringArg(values, "password"),
scope: stringArgOrNull(values, "scope"),
audience: stringArgOrNull(values, "audience"),
credentialsInBody,
});
} else {
throw new Error(`Invalid grant type ${grantType}`);
throw new Error(`Invalid grant type ${String(grantType)}`);
}
const headerName = stringArg(values, 'headerName') || 'Authorization';
const headerValue = `${headerPrefix} ${token.response[tokenName]}`.trim();
const headerName = stringArg(values, "headerName") || "Authorization";
const headerValue = `${headerPrefix} ${token.response[tokenName] ?? ""}`.trim();
return { setHeaders: [{ name: headerName, value: headerValue }] };
},
},
@@ -605,19 +605,19 @@ function stringArgOrNull(
name: string,
): string | null {
const arg = values[name];
if (arg == null || arg === '') return null;
if (arg == null || arg === "") return null;
return `${arg}`;
}
function stringArg(values: Record<string, JsonPrimitive | undefined>, name: string): string {
const arg = stringArgOrNull(values, name);
if (!arg) return '';
if (!arg) return "";
return arg;
}
function intArg(values: Record<string, JsonPrimitive | undefined>, name: string): number | null {
const arg = values[name];
if (arg == null || arg === '') return null;
if (arg == null || arg === "") return null;
const num = parseInt(`${arg}`, 10);
return Number.isNaN(num) ? null : num;
}