fix(HTTP Request Node): Refresh token properly on never fail option (#5861)

* Add handle for simple request options and refresh token

* Remove console.logs

* Add safe check for full response
This commit is contained in:
agobrech 2023-04-05 15:27:04 +02:00 committed by GitHub
parent e7aaa9425a
commit 33c67f45ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1117,7 +1117,6 @@ export async function requestOAuth2(
[oAuth2Options.keyToIncludeInAccessTokenHeader]: token.accessToken, [oAuth2Options.keyToIncludeInAccessTokenHeader]: token.accessToken,
}); });
} }
if (isN8nRequest) { if (isN8nRequest) {
return this.helpers.httpRequest(newRequestOptions).catch(async (error: AxiosError) => { return this.helpers.httpRequest(newRequestOptions).catch(async (error: AxiosError) => {
if (error.response?.status === 401) { if (error.response?.status === 401) {
@ -1179,85 +1178,95 @@ export async function requestOAuth2(
throw error; throw error;
}); });
} }
return this.helpers
return this.helpers.request(newRequestOptions).catch(async (error: IResponseError) => { .request(newRequestOptions)
const statusCodeReturned = .then((response) => {
oAuth2Options?.tokenExpiredStatusCode === undefined const requestOptions = newRequestOptions as any;
? 401 if (
: oAuth2Options?.tokenExpiredStatusCode; requestOptions.resolveWithFullResponse === true &&
requestOptions.simple === false &&
if (error.statusCode === statusCodeReturned) { response.statusCode ===
// Token is probably not valid anymore. So try refresh it. (oAuth2Options?.tokenExpiredStatusCode === undefined
? 401
const tokenRefreshOptions: IDataObject = {}; : oAuth2Options?.tokenExpiredStatusCode)
) {
if (oAuth2Options?.includeCredentialsOnRefreshOnBody) { throw response;
const body: IDataObject = {
client_id: credentials.clientId,
client_secret: credentials.clientSecret,
};
tokenRefreshOptions.body = body;
// Override authorization property so the credentials are not included in it
tokenRefreshOptions.headers = {
Authorization: '',
};
} }
return response;
Logger.debug( })
`OAuth2 token for "${credentialsType}" used by node "${node.name}" expired. Should revalidate.`, .catch(async (error: IResponseError) => {
); const statusCodeReturned =
oAuth2Options?.tokenExpiredStatusCode === undefined
let newToken; ? 401
: oAuth2Options?.tokenExpiredStatusCode;
// if it's OAuth2 with client credentials grant type, get a new token if (error.statusCode === statusCodeReturned) {
// instead of refreshing it. // Token is probably not valid anymore. So try refresh it.
if (OAuth2GrantType.clientCredentials === credentials.grantType) { const tokenRefreshOptions: IDataObject = {};
newToken = await getClientCredentialsToken(token.client, credentials); if (oAuth2Options?.includeCredentialsOnRefreshOnBody) {
} else { const body: IDataObject = {
newToken = await token.refresh(tokenRefreshOptions); client_id: credentials.clientId,
} client_secret: credentials.clientSecret,
};
Logger.debug( tokenRefreshOptions.body = body;
`OAuth2 token for "${credentialsType}" used by node "${node.name}" has been renewed.`, // Override authorization property so the credentials are not included in it
); tokenRefreshOptions.headers = {
Authorization: '',
credentials.oauthTokenData = newToken.data; };
}
// Find the credentials Logger.debug(
if (!node.credentials?.[credentialsType]) { `OAuth2 token for "${credentialsType}" used by node "${node.name}" expired. Should revalidate.`,
throw new Error(
`The node "${node.name}" does not have credentials of type "${credentialsType}"!`,
); );
}
const nodeCredentials = node.credentials[credentialsType];
// Save the refreshed token let newToken;
await additionalData.credentialsHelper.updateCredentials(
nodeCredentials,
credentialsType,
credentials as unknown as ICredentialDataDecryptedObject,
);
Logger.debug( // if it's OAuth2 with client credentials grant type, get a new token
`OAuth2 token for "${credentialsType}" used by node "${node.name}" has been saved to database successfully.`, // instead of refreshing it.
); if (OAuth2GrantType.clientCredentials === credentials.grantType) {
newToken = await getClientCredentialsToken(token.client, credentials);
} else {
newToken = await token.refresh(tokenRefreshOptions);
}
Logger.debug(
`OAuth2 token for "${credentialsType}" used by node "${node.name}" has been renewed.`,
);
// Make the request again with the new token credentials.oauthTokenData = newToken.data;
const newRequestOptions = newToken.sign(requestOptions as clientOAuth2.RequestObject);
newRequestOptions.headers = newRequestOptions.headers ?? {};
if (oAuth2Options?.keyToIncludeInAccessTokenHeader) { // Find the credentials
Object.assign(newRequestOptions.headers, { if (!node.credentials?.[credentialsType]) {
[oAuth2Options.keyToIncludeInAccessTokenHeader]: token.accessToken, throw new Error(
}); `The node "${node.name}" does not have credentials of type "${credentialsType}"!`,
);
}
const nodeCredentials = node.credentials[credentialsType];
// Save the refreshed token
await additionalData.credentialsHelper.updateCredentials(
nodeCredentials,
credentialsType,
credentials as unknown as ICredentialDataDecryptedObject,
);
Logger.debug(
`OAuth2 token for "${credentialsType}" used by node "${node.name}" has been saved to database successfully.`,
);
// Make the request again with the new token
const newRequestOptions = newToken.sign(requestOptions as clientOAuth2.RequestObject);
newRequestOptions.headers = newRequestOptions.headers ?? {};
if (oAuth2Options?.keyToIncludeInAccessTokenHeader) {
Object.assign(newRequestOptions.headers, {
[oAuth2Options.keyToIncludeInAccessTokenHeader]: token.accessToken,
});
}
return this.helpers.request(newRequestOptions);
} }
return this.helpers.request(newRequestOptions); // Unknown error so simply throw it
} throw error;
});
// Unknown error so simply throw it
throw error;
});
} }
/** /**