Oauth 2 for custom nodes n8n

Describe the issue/error/question

I am trying to do Oauth2 authentication for a custom node. I couldn’t find a detail documentation about it, so I checked other custom nodes and how they do it in this github n8n/packages/nodes-base/credentials at master · n8n-io/n8n · GitHub.

In my case I have to do 3 different call, First for authorization, then getting the access token and last of them to get the refresh token (which n8n should keep refreshing)

Please someone can help me with some more detail documentation or explanation in how to could this be done. Thanks!

Hey @Juan_Cruz_Mancuso_Mi,

Welcome to the community :tada:

If you use the OAuth credential type you don’t need to worry about the calls as we automatically handle them. You can take any of the oauth2 credentials and just replace the values as needed and you should be all good.

Hey @Jon, Thanks for the welcome!

I don’t know how to pass do the calls inside of Oauth2Api.credentials.ts

For example, when doing credentials inside Zapier I would do something like this:
config: {
type: “oauth2”,
oauth2Config: {
authorizeUrl: {
method: “GET”,
url: url/oauth/authorize,
params: {
response_type: “code”,
redirect_uri: “{{bundle.inputData.redirect_uri}}”,
},
},
getAccessToken: {
url: url/oauth/token,
method: “POST”,
headers: {
“content-type”: “application/x-www-form-urlencoded”,
accept: “application/json”,
},
body: {
code: “{{bundle.inputData.code}}”,
grant_type: “authorization_code”,
},
removeMissingValuesFrom: {},
},
refreshAccessToken: {
url: url/oauth/token,
method: “POST”,
body: {
refresh_token: “{{bundle.authData.refresh_token}}”,
grant_type: “refresh_token”,
},
headers: {
“content-type”: “application/x-www-form-urlencoded”,
accept: “application/json”,
},
},
},

But here credentials look like this:

properties: INodeProperties[] = [
{
displayName: ‘Grant Type’,
name: ‘grantType’,
type: ‘hidden’,
default: ‘authorizationCode’,
},
{
displayName: ‘Authorization URL’,
name: ‘authUrl’,
type: ‘hidden’,
default: ‘url/oauth/authorize’,
required: true,
},
{
displayName: ‘Redirect URI’,
name: ‘redirect_uri’,
type: ‘hidden’,
default: ‘url/oauth/token’,
required: true,
},
{
displayName: ‘Access Token URL’,
name: ‘accessTokenUrl’,
type: ‘hidden’,
default: ‘url/oauth/token’,
required: true,
},
{
displayName: ‘Scope’,
name: ‘scope’,
type: ‘hidden’,
default: ‘’,
},
{
displayName: ‘Auth URI Query Parameters’,
name: ‘authQueryParameters’,
type: ‘hidden’,
default: ‘’,
},
{
displayName: ‘Authentication’,
name: ‘authentication’,
type: ‘hidden’,
default: ‘body’,
},
];

Where should I pass the headers, parameters, body, method? So that N8N can handle the oAuth2.

Hey @Juan_Cruz_Mancuso_Mi,

Based on your Zapier example it would be the below, The names of the fields are almost the same. Internally we will work out the headers so you don’t need to worry about that and we will handle the token refresh.

import { ICredentialType, INodeProperties } from 'n8n-workflow';

export class YourNodeOAuth2Api implements ICredentialType {
	name = 'yourNodeOAuth2Api';
	extends = ['oAuth2Api'];
	displayName = 'YourNode OAuth2 API';
	documentationUrl = '';
	properties: INodeProperties[] = [
		{
			displayName: 'Grant Type',
			name: 'grantType',
			type: 'hidden',
			default: 'authorizationCode',
		},
		{
			displayName: 'Authorization URL',
			name: 'authUrl',
			type: 'hidden',
			default: 'url/oauth/authorize',
			required: true,
		},
		{
			displayName: 'Access Token URL',
			name: 'accessTokenUrl',
			type: 'hidden',
			default: 'url/oauth/token',
			required: true,
		},
		{
			displayName: 'Scope',
			name: 'scope',
			type: 'hidden',
			default: '',
			required: true,
		},
		{
			displayName: 'Auth URI Query Parameters',
			name: 'authQueryParameters',
			type: 'hidden',
			default: '',
		},
		{
			displayName: 'Authentication',
			name: 'authentication',
			type: 'hidden',
			default: 'body',
		},
	];
}
1 Like

Thanks Jon for the rapid response! @Jon
I am getting some inputs for client_id and client_secret. But how can I handle this data. Because I need to do this 3 different calls and handle I need the user to sign inside metamask. I saw some other examples where they handle this inside a file name GenericFunction. There is some documentation for this? or what is the standard for this.

Hey @Juan_Cruz_Mancuso_Mi,

Normally GenericFunction is used to call the HTTP API but to call it you would normally use…

return await this.helpers.requestWithAuthentication.call(this, 'yourNodeOAuth2Api', options);

From there requestWithAuthentication will internally handle the OAuth process and get a new token so you don’t need to worry about it.

Out of interest what 3 calls do you need to handle? We will automatically call the Authorization URL, Access Token URL and Refresh Token URL (which is normally the same as the Access Token URL) so you don’t need to worry about these.

Hey @Jon, hope you are doing well!

For example, the authUrl call needs to be a “GET” and should have inside params this value: response_type: “code”.
The accessTokenUrl and the refreshAccessToken have different headers and body. Where I put this?

Also the app is asking for a client_id and client_secret which I am not using in any of the calls, how I get rid of them?

Thanks!

Hey @Juan_Cruz_Mancuso_Mi,

You don’t need to worry about the authURL call we automatically do that, Generally speaking the oauth standard is mostly the same so the example above would work with almost every implementation and you wouldn’t need to change a thing.

Not having a client id or client secret is a new one that I have ran into before, Do you have a link to the docs for what you are implementing? I am not sure why they wouldn’t have it, This also means I will need to tag @marcus and @RicardoE105 into this one as they may have an idea on how to hide / remove those 2 fields.

Hey @Jon,

This is the auth documentation. Would be great if you could help me.

  1. Authentication page

A page for user authentication where metamask signing is already implemented

Page url: url/oauth/authorize

Required query params:

  • redirect_uri
  • response_type = “code”

Once authenticated, a user will be redirected to the “redirect_uri”.

The “code” string that can be exchanged in get access token for an access_token that will be added as a query param to the redirect url.

Example: url?code=xxxxxxxxx…

2- get access token

URL: url/oauth/token

Method: POST

Body props:

  • grant_type - ‘authorization_code’
  • code - base64 encoded JSON string containing auth message and signature {“message”:“xxx”, “signature”: “xxx”}

Response props:

  1. access_token
  2. refresh_token
  3. expires_in
  4. token_type

3- refresh access token

URL: url/oauth/token

Method: POST

Body props:

  • grant_type - ‘refresh_token’
  • refresh_token - refresh_token returned in the access token request.

Response props:

  1. access_token
  2. expires_in
  3. token_type

Sorry for the late response and thanks for the help.

Juan

@marcus and @RicardoE105 Can you help me to handle this oauth authentication?

Your credentials file should look like this based on the data you provided. You do not need to make any of the calls in the documentation since we do that for you behind the scenes. You have to:

  1. Create the credentials file, as shown below.
  2. Assign the credentials to the node. You can do this by adding the newly created credentials to the credential’s property in the node file.
  3. Make sure all the calls use to the API use this.helpers.requestwithAuthentication, as Jonathan already mentioned.

Once that is done, whoever is using the node has to provide the data for the credentials. in this case, it will be the client_id and client_secret.

Does that make sense?

Iimport { ICredentialType, INodeProperties } from 'n8n-workflow';

export class ToolNameOAuth2Api implements ICredentialType {
	name = 'toolNameOAuth2Api';
	extends = ['oAuth2Api'];
	displayName = 'Toolname OAuth2 API';
	documentationUrl = 'toolname';
	properties: INodeProperties[] = [
		{
			displayName: 'Grant Type',
			name: 'grantType',
			type: 'hidden',
			default: 'authorizationCode',
		},
		{
			displayName: 'Authorization URL',
			name: 'authUrl',
			type: 'hidden',
			default: 'url/oauth/authorize',
		},
		{
			displayName: 'Access Token URL',
			name: 'accessTokenUrl',
			type: 'hidden',
			default: 'url/oauth/token',
		},
		{
			displayName: 'Auth URI Query Parameters',
			name: 'authQueryParameters',
			type: 'hidden',
			default: '',
		},
		{
			displayName: 'Authentication',
			name: 'authentication',
			type: 'hidden',
			default: 'body',
		},
		{
			displayName: 'Scope',
			name: 'scope',
			type: 'hidden',
			default: '',
		},
	];
}