AOAuth2Application

Overview #

AOAuth2Application is the base class for creating applications that use OAuth2 authentication. It handles the OAuth2 authorization flow, token management, and token refresh automatically.

Purpose:

  • Implement OAuth2 authentication flow
  • Manage access and refresh tokens
  • Handle token expiration and refresh
  • Provide authorized API requests

Location: orchesty-nodejs-sdk/lib/Authorization/Type/OAuth2/AOAuth2Application.ts

When to Use #

Use AOAuth2Application for services that authenticate with OAuth2:

  • Google APIs
  • Facebook API
  • GitHub API
  • Salesforce
  • Any API using OAuth 2.0 authorization

Don't use for static credentials - use ABasicApplication instead.

Class Hierarchy #

AApplication
AOAuth2Application (You extend this)
YourOAuth2Application (e.g., GoogleApplication, GitHubApplication)

Constructor #

constructor(protected provider: OAuth2Provider)

Parameters:

ParameterTypeDescription
providerOAuth2ProviderOAuth2 provider service (injected from DI container)

Example:

import { OAuth2Provider } from '../../lib/Authorization/Provider/OAuth2/OAuth2Provider';
import AOAuth2Application from '../../lib/Authorization/Type/OAuth2/AOAuth2Application';

export default class GoogleApplication extends AOAuth2Application {
    // Provider is passed to parent constructor
}

// When registering:
const oauth2Provider = container.get(OAuth2Provider);
const googleApp = new GoogleApplication(oauth2Provider);

Abstract Methods You Must Implement #

getName() #

public abstract getName(): string

Returns the unique application identifier.

getPublicName() #

public abstract getPublicName(): string

Returns the display name.

getDescription() #

public abstract getDescription(): string

Returns the application description.

getAuthUrl() #

public abstract getAuthUrl(): string

Returns the OAuth2 authorization URL.

Example:

public getAuthUrl(): string {
    return 'https://accounts.google.com/o/oauth2/v2/auth';
}

getTokenUrl() #

public abstract getTokenUrl(): string

Returns the OAuth2 token exchange URL.

Example:

public getTokenUrl(): string {
    return 'https://oauth2.googleapis.com/token';
}

getScopes() #

public abstract getScopes(applicationInstall: ApplicationInstall): string[]

Returns the OAuth2 scopes to request.

Parameters:

ParameterTypeDescription
applicationInstallApplicationInstallUser installation

Returns: string[] - Array of scope strings

Example:

public getScopes(applicationInstall: ApplicationInstall): string[] {
    return [
        'https://www.googleapis.com/auth/userinfo.email',
        'https://www.googleapis.com/auth/drive.readonly'
    ];
}

getFormStack() #

public abstract getFormStack(): FormStack

Defines the OAuth2 configuration form (client ID, client secret).

Example:

import CoreFormsEnum from '../../lib/Application/Base/CoreFormsEnum';
import Field from '../../lib/Application/Model/Form/Field';
import FieldType from '../../lib/Application/Model/Form/FieldType';
import Form from '../../lib/Application/Model/Form/Form';
import FormStack from '../../lib/Application/Model/Form/FormStack';
import { CLIENT_ID, CLIENT_SECRET } from '../../lib/Authorization/Type/OAuth2/IOAuth2Application';

public getFormStack(): FormStack {
    const clientIdField = new Field(FieldType.TEXT, CLIENT_ID, 'Client ID');
    const clientSecretField = new Field(FieldType.PASSWORD, CLIENT_SECRET, 'Client Secret');

    const form = new Form(CoreFormsEnum.AUTHORIZATION_FORM, 'Authorization');
    form.addField(clientIdField);
    form.addField(clientSecretField);

    const formStack = new FormStack();
    formStack.addForm(form);
    
    return formStack;
}

getRequestDto() #

public abstract getRequestDto(
    dto: ProcessDto,
    applicationInstall: ApplicationInstall,
    method: HttpMethods,
    url?: string,
    data?: unknown
): RequestDto | Promise<RequestDto>

Creates an authenticated request with the OAuth access token.

Example:

public getRequestDto(
    dto: ProcessDto,
    applicationInstall: ApplicationInstall,
    method: HttpMethods,
    url?: string,
    data?: unknown
): RequestDto {
    const accessToken = this.getAccessToken(applicationInstall);
    
    const requestDto = new RequestDto(url ?? '', method, dto, data);
    requestDto.setHeaders({
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
    });
    
    return requestDto;
}

Inherited Methods #

getAccessToken() #

public getAccessToken(applicationInstall: ApplicationInstall): string

Gets the current access token from settings.

Throws: Error if token doesn't exist

authorize() #

public authorize(applicationInstall: ApplicationInstall): string

Generates the OAuth2 authorization URL for user to visit.

setAuthorizationToken() #

public async setAuthorizationToken(
    applicationInstall: ApplicationInstall,
    token: Record<string, string>
): Promise<void>

Exchanges authorization code for access token.

refreshAuthorization() #

public async refreshAuthorization(applicationInstall: ApplicationInstall): Promise<ApplicationInstall>

Refreshes an expired access token using refresh token.

isAuthorized() #

public isAuthorized(applicationInstall: ApplicationInstall): boolean

Checks if application has a valid access token.

getScopesSeparator() #

protected getScopesSeparator(): string

Returns scope separator (default: comma). Override if API uses different separator.

Example:

import ScopeSeparatorEnum from '../../lib/Authorization/ScopeSeparatorEnum';

protected getScopesSeparator(): string {
    return ScopeSeparatorEnum.SPACE;  // For APIs that use space-separated scopes
}

Usage Examples #

Complete OAuth2 Application #

From: orchesty-nodejs-sdk/test/Application/TestOAuth2Application.ts

import CoreFormsEnum from '../../lib/Application/Base/CoreFormsEnum';
import { ApplicationInstall } from '../../lib/Application/Database/ApplicationInstall';
import Field from '../../lib/Application/Model/Form/Field';
import FieldType from '../../lib/Application/Model/Form/FieldType';
import Form from '../../lib/Application/Model/Form/Form';
import FormStack from '../../lib/Application/Model/Form/FormStack';
import ScopeSeparatorEnum from '../../lib/Authorization/ScopeSeparatorEnum';
import AOAuth2Application from '../../lib/Authorization/Type/OAuth2/AOAuth2Application';
import { CLIENT_ID, CLIENT_SECRET } from '../../lib/Authorization/Type/OAuth2/IOAuth2Application';
import RequestDto from '../../lib/Transport/Curl/RequestDto';
import { HttpMethods } from '../../lib/Transport/HttpMethods';
import ProcessDto from '../../lib/Utils/ProcessDto';

export default class TestOAuth2Application extends AOAuth2Application {

    public getAuthUrl(): string {
        return 'https://identity.idoklad.cz/server/connect/authorize';
    }

    public getDescription(): string {
        return 'Test OAuth2 application';
    }

    public getName(): string {
        return 'oauth2application';
    }

    public getPublicName(): string {
        return 'Test OAuth2 Application';
    }

    public getRequestDto(
        dto: ProcessDto,
        applicationInstall: ApplicationInstall,
        method: HttpMethods,
        url?: string,
        data?: unknown
    ): RequestDto {
        const accessToken = this.getAccessToken(applicationInstall);
        
        const requestDto = new RequestDto(url ?? '', method, dto, data);
        requestDto.setHeaders({
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json'
        });
        
        return requestDto;
    }

    public getFormStack(): FormStack {
        const clientIdField = new Field(FieldType.TEXT, CLIENT_ID, 'Client ID');
        const clientSecretField = new Field(FieldType.PASSWORD, CLIENT_SECRET, 'Client Secret');

        const form = new Form(CoreFormsEnum.AUTHORIZATION_FORM, 'Authorization');
        form.addField(clientIdField);
        form.addField(clientSecretField);

        const formStack = new FormStack();
        formStack.addForm(form);
        
        return formStack;
    }

    public getTokenUrl(): string {
        return 'https://identity.idoklad.cz/server/connect/token';
    }

    public getScopes(applicationInstall: ApplicationInstall): string[] {
        return ['idoklad_api', 'offline_access'];
    }

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

Using OAuth2 in Connector #

export default class GoogleDriveConnector extends AConnector {
    
    public async processAction(dto: ProcessDto): Promise<ProcessDto> {
        const appInstall = await this.getApplicationInstallFromProcess(dto);
        const app = this.getApplication<GoogleApplication>();
        
        // Check if token is still valid
        const expires = appInstall.getExpires();
        if (expires && expires < new Date()) {
            // Token expired - refresh it
            const refreshedInstall = await app.refreshAuthorization(appInstall);
            // Update in database
            await this.getDbClient()
                .getApplicationRepository()
                .update(refreshedInstall);
        }
        
        // Make authorized request
        const requestDto = app.getRequestDto(
            dto,
            appInstall,
            HttpMethods.GET,
            'https://www.googleapis.com/drive/v3/files'
        );
        
        const responseDto = await this.getSender().send(requestDto);
        dto.setData(responseDto.getBody());
        
        return dto;
    }
}

OAuth2 Flow #

1. User Authorization #

User clicks "Connect" 
    ↓
System calls authorize() 
    ↓
User redirected to OAuth2 provider 
    ↓
User grants permissions 
    ↓
Provider redirects back with authorization code

2. Token Exchange #

System receives authorization code 
    ↓
Calls setAuthorizationToken() 
    ↓
Exchanges code for access token + refresh token 
    ↓
Tokens stored in ApplicationInstall

3. Making Requests #

Connector needs to call API 
    ↓
Gets ApplicationInstall 
    ↓
Calls getRequestDto() with ApplicationInstall 
    ↓
Access token added to Authorization header 
    ↓
Request sent to API

4. Token Refresh (when expired) #

Access token expired 
    ↓
Calls refreshAuthorization() 
    ↓
Uses refresh token to get new access token 
    ↓
New tokens stored in ApplicationInstall

Common Patterns #

Pattern 1: Custom Authorization Options #

protected getProviderCustomOptions(applicationInstall: ApplicationInstall): Record<string, unknown> {
    return {
        options: {
            authorizationMethod: 'body',  // or 'header'
            bodyFormat: 'json',            // or 'form'
        },
        // Additional provider-specific options
        prompt: 'consent',
        access_type: 'offline'
    };
}

Pattern 2: Dynamic Scopes #

public getScopes(applicationInstall: ApplicationInstall): string[] {
    const settings = applicationInstall.getNonEncryptedSettings();
    const baseScopes = ['email', 'profile'];
    
    // Add optional scopes based on configuration
    if (settings['enable_drive']) {
        baseScopes.push('https://www.googleapis.com/auth/drive');
    }
    
    if (settings['enable_calendar']) {
        baseScopes.push('https://www.googleapis.com/auth/calendar');
    }
    
    return baseScopes;
}

Pattern 3: API Versioning #

public getRequestDto(
    dto: ProcessDto,
    applicationInstall: ApplicationInstall,
    method: HttpMethods,
    url?: string,
    data?: unknown
): RequestDto {
    const accessToken = this.getAccessToken(applicationInstall);
    const settings = applicationInstall.getNonEncryptedSettings();
    const apiVersion = settings['api_version'] || 'v1';
    
    // Prepend version to URL if not already present
    const fullUrl = url?.includes('://') ? url : `https://api.example.com/${apiVersion}${url}`;
    
    const requestDto = new RequestDto(fullUrl, method, dto, data);
    requestDto.setHeaders({
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
    });
    
    return requestDto;
}

Next Steps #

  1. ABasicApplication - For simple authentication
  2. FormStack - Build configuration forms
  3. ApplicationInstall - How tokens are stored
  4. DIContainer - Register your application
  5. OAuth2Provider - OAuth2 provider service

See Also #

© 2025 Orchesty Solutions. All rights reserved.