diff --git a/packages/nodes-base/credentials/LinearOAuth2Api.credentials.ts b/packages/nodes-base/credentials/LinearOAuth2Api.credentials.ts new file mode 100644 index 0000000000..b1e22ddfd9 --- /dev/null +++ b/packages/nodes-base/credentials/LinearOAuth2Api.credentials.ts @@ -0,0 +1,73 @@ +import type { ICredentialType, INodeProperties } from 'n8n-workflow'; + +const scopes = ['read', 'write', 'issues:create', 'comments:create']; + +export class LinearOAuth2Api implements ICredentialType { + name = 'linearOAuth2Api'; + + extends = ['oAuth2Api']; + + displayName = 'Linear OAuth2 API'; + + documentationUrl = 'linear'; + + properties: INodeProperties[] = [ + { + displayName: 'Grant Type', + name: 'grantType', + type: 'hidden', + default: 'authorizationCode', + }, + { + displayName: 'Authorization URL', + name: 'authUrl', + type: 'hidden', + default: 'https://linear.app/oauth/authorize', + required: true, + }, + { + displayName: 'Access Token URL', + name: 'accessTokenUrl', + type: 'hidden', + default: 'https://api.linear.app/oauth/token', + required: true, + }, + { + displayName: 'Actor', + name: 'actor', + type: 'options', + options: [ + { + name: 'User', + value: 'user', + description: 'Resources are created as the user who authorized the application', + }, + { + name: 'Application', + value: 'application', + description: 'Resources are created as the application', + }, + ], + default: 'user', + }, + { + displayName: 'Scope', + name: 'scope', + type: 'hidden', + default: scopes.join(' '), + required: true, + }, + { + displayName: 'Auth URI Query Parameters', + name: 'authQueryParameters', + type: 'hidden', + default: '={{"actor="+$self["actor"]}}', + }, + { + displayName: 'Authentication', + name: 'authentication', + type: 'hidden', + default: 'body', + }, + ]; +} diff --git a/packages/nodes-base/nodes/Linear/GenericFunctions.ts b/packages/nodes-base/nodes/Linear/GenericFunctions.ts index da6407520d..2ccd7631a7 100644 --- a/packages/nodes-base/nodes/Linear/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Linear/GenericFunctions.ts @@ -23,6 +23,7 @@ export async function linearApiRequest( option: IDataObject = {}, ): Promise { const endpoint = 'https://api.linear.app/graphql'; + const authenticationMethod = this.getNodeParameter('authentication', 0, 'apiToken') as string; let options: OptionsWithUri = { headers: { @@ -35,7 +36,11 @@ export async function linearApiRequest( }; options = Object.assign({}, options, option); try { - return await this.helpers.requestWithAuthentication.call(this, 'linearApi', options); + return await this.helpers.requestWithAuthentication.call( + this, + authenticationMethod === 'apiToken' ? 'linearApi' : 'linearOAuth2Api', + options, + ); } catch (error) { throw new NodeApiError(this.getNode(), error as JsonObject); } diff --git a/packages/nodes-base/nodes/Linear/Linear.node.ts b/packages/nodes-base/nodes/Linear/Linear.node.ts index 2c34b259f3..4cd7035576 100644 --- a/packages/nodes-base/nodes/Linear/Linear.node.ts +++ b/packages/nodes-base/nodes/Linear/Linear.node.ts @@ -46,9 +46,39 @@ export class Linear implements INodeType { name: 'linearApi', required: true, testedBy: 'linearApiTest', + displayOptions: { + show: { + authentication: ['apiToken'], + }, + }, + }, + { + name: 'linearOAuth2Api', + required: true, + displayOptions: { + show: { + authentication: ['oAuth2'], + }, + }, }, ], properties: [ + { + displayName: 'Authentication', + name: 'authentication', + type: 'options', + options: [ + { + name: 'API Token', + value: 'apiToken', + }, + { + name: 'OAuth2', + value: 'oAuth2', + }, + ], + default: 'apiToken', + }, { displayName: 'Resource', name: 'resource', diff --git a/packages/nodes-base/nodes/Linear/LinearTrigger.node.ts b/packages/nodes-base/nodes/Linear/LinearTrigger.node.ts index 273a2c11b7..643f6b70b8 100644 --- a/packages/nodes-base/nodes/Linear/LinearTrigger.node.ts +++ b/packages/nodes-base/nodes/Linear/LinearTrigger.node.ts @@ -29,6 +29,20 @@ export class LinearTrigger implements INodeType { name: 'linearApi', required: true, testedBy: 'linearApiTest', + displayOptions: { + show: { + authentication: ['apiToken'], + }, + }, + }, + { + name: 'linearOAuth2Api', + required: true, + displayOptions: { + show: { + authentication: ['oAuth2'], + }, + }, }, ], webhooks: [ @@ -40,6 +54,22 @@ export class LinearTrigger implements INodeType { }, ], properties: [ + { + displayName: 'Authentication', + name: 'authentication', + type: 'options', + options: [ + { + name: 'API Token', + value: 'apiToken', + }, + { + name: 'OAuth2', + value: 'oAuth2', + }, + ], + default: 'apiToken', + }, { displayName: 'Team Name or ID', name: 'teamId', diff --git a/packages/nodes-base/package.json b/packages/nodes-base/package.json index 9fe5a506b1..0c0b55cff1 100644 --- a/packages/nodes-base/package.json +++ b/packages/nodes-base/package.json @@ -188,6 +188,7 @@ "dist/credentials/Ldap.credentials.js", "dist/credentials/LemlistApi.credentials.js", "dist/credentials/LinearApi.credentials.js", + "dist/credentials/LinearOAuth2Api.credentials.js", "dist/credentials/LineNotifyOAuth2Api.credentials.js", "dist/credentials/LingvaNexApi.credentials.js", "dist/credentials/LinkedInOAuth2Api.credentials.js",