Skip to main content
Version: Current

OAuth2 Application

In this tutorial we'll implement an Application with OAuth 2.0 authorization, which is today probably the most used authorization to SaaS. Both OAuth1 and OAuth2 are handled via GUI. Within Admin Orchesty creates complete form including redirect to integrated service. We chose HubSpot CRM for this tutorial.

Prerequisites

Application create

First, we create the AOAuth2Application extension application and complete all the basic methods described in the Basic Application tutorial. We also prepare a form for entering access credentials for authorization.

import CoreFormsEnum, { getFormName } from '@orchesty/nodejs-sdk/dist/lib/Application/Base/CoreFormsEnum';
import { ApplicationInstall } from '@orchesty/nodejs-sdk/dist/lib/Application/Database/ApplicationInstall';
import Field from '@orchesty/nodejs-sdk/dist/lib/Application/Model/Form/Field';
import FieldType from '@orchesty/nodejs-sdk/dist/lib/Application/Model/Form/FieldType';
import Form from '@orchesty/nodejs-sdk/dist/lib/Application/Model/Form/Form';
import FormStack from '@orchesty/nodejs-sdk/dist/lib/Application/Model/Form/FormStack';
import AOAuth2Application from '@orchesty/nodejs-sdk/dist/lib/Authorization/Type/OAuth2/AOAuth2Application';
import { CLIENT_ID, CLIENT_SECRET } from '@orchesty/nodejs-sdk/dist/lib/Authorization/Type/OAuth2/IOAuth2Application';
import RequestDto from '@orchesty/nodejs-sdk/dist/lib/Transport/Curl/RequestDto';
import { HttpMethods } from '@orchesty/nodejs-sdk/dist/lib/Transport/HttpMethods';
import AProcessDto from '@orchesty/nodejs-sdk/dist/lib/Utils/AProcessDto';

const APP_ID = 'app_id';
export const BASE_URL = 'https://api.hubapi.com';
export const NAME = 'hub-spot';

export default class HubSpotApplication extends AOAuth2Application {

public getName(): string {
return NAME;
}

public getPublicName(): string {
return 'HubSpot';
}

public getDescription(): string {
return 'HubSpot application with OAuth 2';
}

public getRequestDto(
dto: AProcessDto,
applicationInstall: ApplicationInstall,
method: HttpMethods,
url?: string,
data?: unknown,
): RequestDto {
// Implementated in next stepts
}

public getFormStack(): FormStack {
const form = new Form(CoreFormsEnum.AUTHORIZATION_FORM, getFormName(CoreFormsEnum.AUTHORIZATION_FORM))
.addField(new Field(FieldType.TEXT, CLIENT_ID, 'Client Id', null, true))
.addField(new Field(FieldType.TEXT, CLIENT_SECRET, 'Client Secret', null, true))
.addField(new Field(FieldType.TEXT, APP_ID, 'Application Id', null, true));

return new FormStack().addForm(form);
}
// ...

}

OAuth2 authorization

Following steps are unique for OAuth2 authorization, which are required to correctly set up an application for token fetching.

// ...
import { ApplicationInstall } from '@orchesty/nodejs-sdk/dist/lib/Application/Database/ApplicationInstall';
import AOAuth2Application from '@orchesty/nodejs-sdk/dist/lib/Authorization/Type/OAuth2/AOAuth2Application';
import ScopeSeparatorEnum from '@orchesty/nodejs-sdk/dist/lib/Authorization/ScopeSeparatorEnum';
// ...

export default class HubSpotApplication extends AOAuth2Application {
// ...

public getAuthUrl(): string {
return 'https://app.hubspot.com/oauth/authorize';
}

public getTokenUrl(): string {
return 'https://api.hubapi.com/oauth/v1/token';
}

public getScopes(applicationInstall: ApplicationInstall): string[] {
return ['contacts'];
}

protected getScopesSeparator(): string {
return ScopeSeparatorEnum.SPACE;
}

//...

}

RequestDto

Now we'll correctly implement Authorization for requestDto.

// ...
import { CommonHeaders, JSON_TYPE } from '@orchesty/nodejs-sdk/dist/lib/Utils/Headers';
// ...

export default class HubSpotApplication extends AOAuth2Application {
//...

public getRequestDto(
dto: AProcessDto,
applicationInstall: ApplicationInstall,
method: HttpMethods,
url?: string,
data?: unknown,
): RequestDto {
const headers = {
[CommonHeaders.CONTENT_TYPE]: JSON_TYPE,
[CommonHeaders.ACCEPT]: JSON_TYPE,
[CommonHeaders.AUTHORIZATION]: `Bearer ${this.getAccessToken(applicationInstall)}`,
};

return new RequestDto(url ?? BASE_URL, method, dto, data, headers);
}

//...

}

Full application code

That's the HubSpot application ready to go. You can copy the full application code here:

import CoreFormsEnum, { getFormName } from '@orchesty/nodejs-sdk/dist/lib/Application/Base/CoreFormsEnum';
import { ApplicationInstall } from '@orchesty/nodejs-sdk/dist/lib/Application/Database/ApplicationInstall';
import Field from '@orchesty/nodejs-sdk/dist/lib/Application/Model/Form/Field';
import FieldType from '@orchesty/nodejs-sdk/dist/lib/Application/Model/Form/FieldType';
import Form from '@orchesty/nodejs-sdk/dist/lib/Application/Model/Form/Form';
import FormStack from '@orchesty/nodejs-sdk/dist/lib/Application/Model/Form/FormStack';
import AOAuth2Application from '@orchesty/nodejs-sdk/dist/lib/Authorization/Type/OAuth2/AOAuth2Application';
import ScopeSeparatorEnum from '@orchesty/nodejs-sdk/dist/lib/Authorization/ScopeSeparatorEnum';
import { CLIENT_ID, CLIENT_SECRET } from '@orchesty/nodejs-sdk/dist/lib/Authorization/Type/OAuth2/IOAuth2Application';
import RequestDto from '@orchesty/nodejs-sdk/dist/lib/Transport/Curl/RequestDto';
import { HttpMethods } from '@orchesty/nodejs-sdk/dist/lib/Transport/HttpMethods';
import AProcessDto from '@orchesty/nodejs-sdk/dist/lib/Utils/AProcessDto';
import { CommonHeaders, JSON_TYPE } from '@orchesty/nodejs-sdk/dist/lib/Utils/Headers';

const APP_ID = 'app_id';
export const BASE_URL = 'https://api.hubapi.com';
export const NAME = 'hub-spot';

export default class HubSpotApplication extends AOAuth2Application {

public getName(): string {
return NAME;
}

public getPublicName(): string {
return 'HubSpot';
}

public getAuthUrl(): string {
return 'https://app.hubspot.com/oauth/authorize';
}

public getTokenUrl(): string {
return 'https://api.hubapi.com/oauth/v1/token';
}

public getDescription(): string {
return 'HubSpot application with OAuth 2';
}

public getRequestDto(
dto: AProcessDto,
applicationInstall: ApplicationInstall,
method: HttpMethods,
url?: string,
data?: unknown,
): RequestDto {
const headers = {
[CommonHeaders.CONTENT_TYPE]: JSON_TYPE,
[CommonHeaders.ACCEPT]: JSON_TYPE,
[CommonHeaders.AUTHORIZATION]: `Bearer ${this.getAccessToken(applicationInstall)}`,
};

return new RequestDto(url ?? BASE_URL, method, dto, data, headers);
}

public getFormStack(): FormStack {
const form = new Form(CoreFormsEnum.AUTHORIZATION_FORM, getFormName(CoreFormsEnum.AUTHORIZATION_FORM))
.addField(new Field(FieldType.TEXT, CLIENT_ID, 'Client Id', null, true))
.addField(new Field(FieldType.TEXT, CLIENT_SECRET, 'Client Secret', null, true))
.addField(new Field(FieldType.TEXT, APP_ID, 'Application Id', null, true));

return new FormStack().addForm(form);
}

public getScopes(applicationInstall: ApplicationInstall): string[] {
return ['contacts'];
}

protected getScopesSeparator(): string {
return ScopeSeparatorEnum.SPACE;
}
}

Register into container

We must not forget to register the application to the container.

Register the application in index.ts to the container.

// ...
import { OAuth2Provider } from '@orchesty/nodejs-sdk/dist/lib/Authorization/Provider/OAuth2/OAuth2Provider';
import { container, initiateContainer } from '@orchesty/nodejs-sdk';
import HubSpotApplication from './HubSpotApplication';

export default function prepare(): void {
initiateContainer();

const oAuth2Provider = container.get(OAuth2Provider);

// ...
const hubSpotApplication = new HubSpotApplication(oAuth2Provider);
container.setApplication(hubSpotApplication);
}

If we have done everything correctly, we will now see the new app in the marketplace. We install the app and in the settings we will see the authorization form we created.

ApplicationApplication

If we already have HubSpot credentials, we can authorize the installed application and it will be ready for use.

Connector creation

tip

We recommend to first check out Connector tutorial to see how create connector to remove API.

Now we create a connector that inserts a new contact into the HubSpot. The whole connector is very simple, if we have already created connectors in the previous tutorials, this should be a piece of cake for us. So let's show the whole code right away:

import AConnector from '@orchesty/nodejs-sdk/dist/lib/Connector/AConnector';
import logger from '@orchesty/nodejs-sdk/dist/lib/Logger/Logger';
import { HttpMethods } from '@orchesty/nodejs-sdk/dist/lib/Transport/HttpMethods';
import ProcessDto from '@orchesty/nodejs-sdk/dist/lib/Utils/ProcessDto';
import { BASE_URL } from './HubSpotApplication';

export const NAME = 'hub-spot-create-contact';

export default class HubSpotCreateContactConnector extends AConnector {

public getName(): string {
return NAME;
}

public async processAction(dto: ProcessDto): Promise<ProcessDto> {
const applicationInstall = await this.getApplicationInstallFromProcess(dto);

const request = await this.getApplication().getRequestDto(
dto,
applicationInstall,
HttpMethods.POST,
`${BASE_URL}/crm/v3/objects/contacts`,
dto.getData(),
);

const response = await this.getSender().send<IResponse>(request, [201, 409]);

if (response.getResponseCode() === 409) {
const email = dto.getJsonData();
logger.error(`Contact "${email}" already exist.`, dto);
}

return dto.setData(response.getBody());
}

}

interface IResponse {
properties: {
email: string;
};
}

In the send() method we can notice a shortened notation for setting up repeated calls. In this case, the connector repeats any calls that return with a different code than we defined. We can use other parameters to set the interval and number of retries. We have left the default values, i.e. 10 repeats per 60 sec.

tip

All about setting up repeat calls can be found in the Results evaluation chapter.

Finally, we set up logging in the connector in case a new contact already exists in HubSpot. How we handle this situation in practice is of course up to us.

tip

We recommend studying the documentation for logging in Orchesty.

Registration of connector

Finally, we register the connector in index.ts to the container.

//...
import HubSpotCreateContactConnector from './HubSpotCreateContactConnector';

export default function prepare(): void {
//...

const hubSpotCreateContactConnector = new HubSpotCreateContactConnector()
.setSender(curlSender)
.setDb(databaseClient)
.setApplication(hubSpotApplication);

container.setConnector(hubSpotCreateContactConnector);

//...
}

We're all set. Now we can test inserting a contact into HubSpot with OAuth 2 authentication.

Test

First, we need to authorize our HubSpot application. In order to gain access using OAuth, we first need to create a developer account in HubSpot and a new application in that account. In the application settings we then get the app ID, client ID and client sercret. We can find instructions on the Hubspot documentation.

We use the credentials to authorize our HubSpot application form in Orchesty Admin.

HubSpot settings

Now we can authorize access to our HubSpot account. Orchesty will redirect us to the authorization form.

Authorize form

If we have successfully authorized access to our HubSpot account, we can activate the application and continue to create the topology.

Creating a topology

The topology to test our example will be really simple this time. We will use the start event and our connector. For this time, we'll enter the data manually. Finally, we add a user task to check the HubSpot response.

Create contact HubSpot topology

We save, publish and activate the topology. On run, we specify the email we will send to HubSpot.

Run topology

Now we can check the new contact in our HubSpot account.