@pakoor/n8n-nodes-instagram 0.1.1 → 0.1.3
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/dist/credentials/InstagramOAuth2Api.credentials.d.ts +11 -10
- package/dist/credentials/InstagramOAuth2Api.credentials.d.ts.map +1 -1
- package/dist/credentials/InstagramOAuth2Api.credentials.js +92 -76
- package/dist/credentials/InstagramOAuth2Api.credentials.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ICredentialDataDecryptedObject, ICredentialTestRequest, ICredentialType, IDataObject, IHttpRequestHelper, INodeProperties } from 'n8n-workflow';
|
|
2
2
|
export declare class InstagramOAuth2Api implements ICredentialType {
|
|
3
3
|
name: string;
|
|
4
|
+
extends: string[];
|
|
4
5
|
displayName: string;
|
|
5
6
|
documentationUrl: string;
|
|
6
|
-
extends: string[];
|
|
7
7
|
properties: INodeProperties[];
|
|
8
|
-
authenticate: IAuthenticateGeneric;
|
|
9
|
-
test: ICredentialTestRequest;
|
|
10
8
|
/**
|
|
11
|
-
* Pre-authentication hook
|
|
12
|
-
* and
|
|
9
|
+
* Pre-authentication hook that exchanges short-lived OAuth token for a long-lived token
|
|
10
|
+
* and refreshes it when near expiration. n8n automatically persists the returned values.
|
|
13
11
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* - 1.6: Auto-discover Instagram Business Account ID
|
|
12
|
+
* This is called by n8n before each API request when the credential has an expirable field.
|
|
13
|
+
* If this function returns new credential data, n8n will persist it to the database.
|
|
17
14
|
*/
|
|
18
|
-
preAuthentication(this: IHttpRequestHelper, credentials: ICredentialDataDecryptedObject): Promise<
|
|
15
|
+
preAuthentication(this: IHttpRequestHelper, credentials: ICredentialDataDecryptedObject): Promise<IDataObject>;
|
|
16
|
+
/**
|
|
17
|
+
* Test the credentials to ensure they work
|
|
18
|
+
*/
|
|
19
|
+
test: ICredentialTestRequest;
|
|
19
20
|
}
|
|
20
21
|
//# sourceMappingURL=InstagramOAuth2Api.credentials.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InstagramOAuth2Api.credentials.d.ts","sourceRoot":"","sources":["../../src/credentials/InstagramOAuth2Api.credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,
|
|
1
|
+
{"version":3,"file":"InstagramOAuth2Api.credentials.d.ts","sourceRoot":"","sources":["../../src/credentials/InstagramOAuth2Api.credentials.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,8BAA8B,EAC9B,sBAAsB,EACtB,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,eAAe,EAChB,MAAM,cAAc,CAAC;AAEtB,qBAAa,kBAAmB,YAAW,eAAe;IACxD,IAAI,SAAwB;IAC5B,OAAO,WAAiB;IACxB,WAAW,SAA0B;IACrC,gBAAgB,SAAwE;IAExF,UAAU,EAAE,eAAe,EAAE,CAgG3B;IAEF;;;;;;OAMG;IACG,iBAAiB,CACrB,IAAI,EAAE,kBAAkB,EACxB,WAAW,EAAE,8BAA8B,GAC1C,OAAO,CAAC,WAAW,CAAC;IA6EvB;;OAEG;IACH,IAAI,EAAE,sBAAsB,CAS1B;CACH"}
|
|
@@ -4,9 +4,9 @@ exports.InstagramOAuth2Api = void 0;
|
|
|
4
4
|
class InstagramOAuth2Api {
|
|
5
5
|
constructor() {
|
|
6
6
|
this.name = 'instagramOAuth2Api';
|
|
7
|
-
this.displayName = 'Instagram OAuth2 API';
|
|
8
|
-
this.documentationUrl = 'https://developers.facebook.com/docs/instagram-api/';
|
|
9
7
|
this.extends = ['oAuth2Api'];
|
|
8
|
+
this.displayName = 'Instagram OAuth2 API';
|
|
9
|
+
this.documentationUrl = 'https://developers.facebook.com/docs/instagram-api/getting-started';
|
|
10
10
|
this.properties = [
|
|
11
11
|
{
|
|
12
12
|
displayName: 'Grant Type',
|
|
@@ -18,19 +18,19 @@ class InstagramOAuth2Api {
|
|
|
18
18
|
displayName: 'Authorization URL',
|
|
19
19
|
name: 'authUrl',
|
|
20
20
|
type: 'hidden',
|
|
21
|
-
default: 'https://
|
|
21
|
+
default: 'https://api.instagram.com/oauth/authorize',
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
displayName: 'Access Token URL',
|
|
25
25
|
name: 'accessTokenUrl',
|
|
26
26
|
type: 'hidden',
|
|
27
|
-
default: 'https://
|
|
27
|
+
default: 'https://api.instagram.com/oauth/access_token',
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
displayName: 'Scope',
|
|
31
31
|
name: 'scope',
|
|
32
32
|
type: 'hidden',
|
|
33
|
-
default: '
|
|
33
|
+
default: 'instagram_business_basic,instagram_business_manage_messages,instagram_business_manage_comments,instagram_business_content_publish',
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
displayName: 'Auth URI Query Parameters',
|
|
@@ -44,13 +44,21 @@ class InstagramOAuth2Api {
|
|
|
44
44
|
type: 'hidden',
|
|
45
45
|
default: 'body',
|
|
46
46
|
},
|
|
47
|
+
{
|
|
48
|
+
displayName: 'Account Information',
|
|
49
|
+
name: 'accountInfoNotice',
|
|
50
|
+
type: 'notice',
|
|
51
|
+
default: '',
|
|
52
|
+
description: 'After connecting your account, your Instagram Business Account details (username, ID, profile) will be automatically available. You can access this information in your workflow nodes. The system will automatically exchange your OAuth token for a long-lived token (60 days) and persist it, ensuring it survives n8n restarts.',
|
|
53
|
+
},
|
|
47
54
|
{
|
|
48
55
|
displayName: 'Client ID',
|
|
49
56
|
name: 'clientId',
|
|
50
57
|
type: 'string',
|
|
51
58
|
default: '',
|
|
52
59
|
required: true,
|
|
53
|
-
description: '
|
|
60
|
+
description: 'The Instagram App ID from your Meta Developer Console. <a href="https://developers.facebook.com/apps/" target="_blank">Get it here</a>.',
|
|
61
|
+
placeholder: '1234567890123456',
|
|
54
62
|
},
|
|
55
63
|
{
|
|
56
64
|
displayName: 'Client Secret',
|
|
@@ -61,116 +69,124 @@ class InstagramOAuth2Api {
|
|
|
61
69
|
},
|
|
62
70
|
default: '',
|
|
63
71
|
required: true,
|
|
64
|
-
description: '
|
|
72
|
+
description: 'The Instagram App Secret from your Meta Developer Console',
|
|
73
|
+
placeholder: 'abc123def456...',
|
|
65
74
|
},
|
|
66
75
|
{
|
|
67
|
-
displayName: '
|
|
68
|
-
name: '
|
|
76
|
+
displayName: 'Webhook Verify Token',
|
|
77
|
+
name: 'webhookVerifyToken',
|
|
69
78
|
type: 'string',
|
|
79
|
+
typeOptions: { password: true },
|
|
70
80
|
default: '',
|
|
71
|
-
|
|
81
|
+
required: false,
|
|
82
|
+
description: 'Optional: Custom verification token for webhook setup (minimum 20 characters). Only needed if using Instagram Trigger node.',
|
|
83
|
+
placeholder: 'my_custom_verify_token_2024',
|
|
72
84
|
},
|
|
85
|
+
// Hidden field for long-lived token with expirable typeOption
|
|
86
|
+
// This enables n8n's preAuthentication system to persist the token
|
|
73
87
|
{
|
|
74
88
|
displayName: 'Long-Lived Token',
|
|
75
89
|
name: 'longLivedToken',
|
|
76
90
|
type: 'hidden',
|
|
77
91
|
typeOptions: {
|
|
78
|
-
|
|
92
|
+
expirable: true,
|
|
79
93
|
},
|
|
80
94
|
default: '',
|
|
81
95
|
},
|
|
82
96
|
{
|
|
83
|
-
displayName: '
|
|
84
|
-
name: '
|
|
85
|
-
type: 'hidden',
|
|
86
|
-
default: 0,
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
displayName: 'Long-Lived Token Created At',
|
|
90
|
-
name: 'longLivedTokenCreatedAt',
|
|
97
|
+
displayName: 'Token Expires At',
|
|
98
|
+
name: 'tokenExpiresAt',
|
|
91
99
|
type: 'hidden',
|
|
92
100
|
default: 0,
|
|
93
101
|
},
|
|
94
102
|
];
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
qs: {
|
|
99
|
-
access_token: '={{$credentials.longLivedToken || $credentials.accessToken}}',
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
};
|
|
103
|
+
/**
|
|
104
|
+
* Test the credentials to ensure they work
|
|
105
|
+
*/
|
|
103
106
|
this.test = {
|
|
104
107
|
request: {
|
|
105
|
-
baseURL: 'https://graph.
|
|
108
|
+
baseURL: 'https://graph.instagram.com/v23.0',
|
|
106
109
|
url: '/me',
|
|
110
|
+
method: 'GET',
|
|
107
111
|
qs: {
|
|
108
|
-
fields: 'id,
|
|
112
|
+
fields: 'id,username',
|
|
109
113
|
},
|
|
110
114
|
},
|
|
111
115
|
};
|
|
112
116
|
}
|
|
113
117
|
/**
|
|
114
|
-
* Pre-authentication hook
|
|
115
|
-
* and
|
|
118
|
+
* Pre-authentication hook that exchanges short-lived OAuth token for a long-lived token
|
|
119
|
+
* and refreshes it when near expiration. n8n automatically persists the returned values.
|
|
116
120
|
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* - 1.6: Auto-discover Instagram Business Account ID
|
|
121
|
+
* This is called by n8n before each API request when the credential has an expirable field.
|
|
122
|
+
* If this function returns new credential data, n8n will persist it to the database.
|
|
120
123
|
*/
|
|
121
124
|
async preAuthentication(credentials) {
|
|
122
|
-
const
|
|
125
|
+
const now = Math.floor(Date.now() / 1000);
|
|
126
|
+
const longLivedToken = credentials.longLivedToken;
|
|
127
|
+
const tokenExpiresAt = credentials.tokenExpiresAt || 0;
|
|
123
128
|
const clientSecret = credentials.clientSecret;
|
|
124
|
-
|
|
125
|
-
|
|
129
|
+
const oauthTokenData = credentials.oauthTokenData;
|
|
130
|
+
const shortLivedToken = oauthTokenData?.access_token;
|
|
131
|
+
// If we have a valid long-lived token that's not near expiration, no action needed
|
|
132
|
+
if (longLivedToken && tokenExpiresAt > 0) {
|
|
133
|
+
// Token is still valid with more than 7 days remaining
|
|
134
|
+
const sevenDaysInSeconds = 7 * 24 * 60 * 60;
|
|
135
|
+
if (tokenExpiresAt > now + sevenDaysInSeconds) {
|
|
136
|
+
return {}; // No update needed
|
|
137
|
+
}
|
|
138
|
+
// Token is valid but near expiration (< 7 days), try to refresh it
|
|
139
|
+
// Instagram allows refresh only if token is at least 24 hours old
|
|
140
|
+
const totalLifetime = 60 * 24 * 60 * 60; // 60 days
|
|
141
|
+
const tokenAge = now - (tokenExpiresAt - totalLifetime);
|
|
142
|
+
if (tokenAge >= 24 * 60 * 60) {
|
|
143
|
+
try {
|
|
144
|
+
const refreshed = (await this.helpers.httpRequest({
|
|
145
|
+
method: 'GET',
|
|
146
|
+
url: 'https://graph.instagram.com/refresh_access_token',
|
|
147
|
+
qs: {
|
|
148
|
+
grant_type: 'ig_refresh_token',
|
|
149
|
+
access_token: longLivedToken,
|
|
150
|
+
},
|
|
151
|
+
}));
|
|
152
|
+
return {
|
|
153
|
+
longLivedToken: refreshed.access_token,
|
|
154
|
+
tokenExpiresAt: now + refreshed.expires_in,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
// Refresh failed, but token is still valid - continue using it
|
|
159
|
+
console.warn('Instagram: Failed to refresh long-lived token, continuing with current token', error);
|
|
160
|
+
return {};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return {}; // Token too new to refresh
|
|
164
|
+
}
|
|
165
|
+
// No long-lived token yet - exchange short-lived OAuth token for long-lived
|
|
166
|
+
if (!shortLivedToken) {
|
|
167
|
+
// No token available at all
|
|
168
|
+
return {};
|
|
126
169
|
}
|
|
127
|
-
const updatedCredentials = { ...credentials };
|
|
128
170
|
try {
|
|
129
|
-
|
|
130
|
-
const longLivedTokenResponse = await this.helpers.httpRequest({
|
|
171
|
+
const exchanged = (await this.helpers.httpRequest({
|
|
131
172
|
method: 'GET',
|
|
132
|
-
url: 'https://graph.
|
|
173
|
+
url: 'https://graph.instagram.com/access_token',
|
|
133
174
|
qs: {
|
|
134
|
-
grant_type: '
|
|
135
|
-
client_id: credentials.clientId,
|
|
175
|
+
grant_type: 'ig_exchange_token',
|
|
136
176
|
client_secret: clientSecret,
|
|
137
|
-
|
|
177
|
+
access_token: shortLivedToken,
|
|
138
178
|
},
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
updatedCredentials.longLivedTokenExpiresAt = now + expiresIn * 1000;
|
|
145
|
-
updatedCredentials.longLivedTokenCreatedAt = now;
|
|
146
|
-
}
|
|
147
|
-
// Step 2: Auto-discover Instagram Business Account ID (Requirement 1.6)
|
|
148
|
-
const tokenToUse = updatedCredentials.longLivedToken || accessToken;
|
|
149
|
-
// Get pages connected to the user
|
|
150
|
-
const pagesResponse = await this.helpers.httpRequest({
|
|
151
|
-
method: 'GET',
|
|
152
|
-
url: 'https://graph.facebook.com/v18.0/me/accounts',
|
|
153
|
-
qs: {
|
|
154
|
-
fields: 'instagram_business_account,id,name',
|
|
155
|
-
access_token: tokenToUse,
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
// Find the first page with an Instagram Business Account
|
|
159
|
-
if (pagesResponse.data && pagesResponse.data.length > 0) {
|
|
160
|
-
for (const page of pagesResponse.data) {
|
|
161
|
-
if (page.instagram_business_account?.id) {
|
|
162
|
-
updatedCredentials.instagramAccountId = page.instagram_business_account.id;
|
|
163
|
-
break;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
}
|
|
179
|
+
}));
|
|
180
|
+
return {
|
|
181
|
+
longLivedToken: exchanged.access_token,
|
|
182
|
+
tokenExpiresAt: now + exchanged.expires_in,
|
|
183
|
+
};
|
|
167
184
|
}
|
|
168
185
|
catch (error) {
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
186
|
+
// Exchange failed - the short-lived token may be expired
|
|
187
|
+
console.error('Instagram: Failed to exchange OAuth token for long-lived token', error);
|
|
188
|
+
return {};
|
|
172
189
|
}
|
|
173
|
-
return updatedCredentials;
|
|
174
190
|
}
|
|
175
191
|
}
|
|
176
192
|
exports.InstagramOAuth2Api = InstagramOAuth2Api;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InstagramOAuth2Api.credentials.js","sourceRoot":"","sources":["../../src/credentials/InstagramOAuth2Api.credentials.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"InstagramOAuth2Api.credentials.js","sourceRoot":"","sources":["../../src/credentials/InstagramOAuth2Api.credentials.ts"],"names":[],"mappings":"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"}
|