Skip to content

Commit

Permalink
Add custom fusion auth client
Browse files Browse the repository at this point in the history
To get a `refreshToken` with the login response we need to ask FushionAuth.
The `@fusionauth/typescript-client` login method does not make that possible.

This commit adds a custom FusionAuth client that would hit the FusionAuth endpoints
directly in cases where we need it.

Signed-off-by: Fon E. Noel NFEBE <[email protected]>
  • Loading branch information
nfebe committed Jul 23, 2023
1 parent f7128fc commit d0b0d38
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 5 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,4 @@ PERMANENT_API_BASE_PATH=${LOCAL_TEMPORARY_AUTH_TOKEN}
# See https://fusionauth.io/docs/v1/tech/apis/api-keys
FUSION_AUTH_HOST=${FUSION_AUTH_HOST}
FUSION_AUTH_KEY=${FUSION_AUTH_KEY}
FUSION_AUTH_APP_ID=${FUSION_AUTH_APP_ID}
10 changes: 7 additions & 3 deletions src/classes/AuthenticationSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { logger } from '../logger';
import {
getFusionAuthClient,
isPartialClientResponse,
FusionAuthApiClient,
} from '../fusionAuth';
import type { KeyboardAuthContext } from 'ssh2';
import type { TwoFactorMethod } from '@fusionauth/typescript-client';
Expand All @@ -19,13 +20,16 @@ export class AuthenticationSession {

private readonly fusionAuthClient;

private readonly FusionAuthApiClient;

private twoFactorId = '';

private twoFactorMethods: TwoFactorMethod[] = [];

public constructor(authContext: KeyboardAuthContext) {
this.authContext = authContext;
this.fusionAuthClient = getFusionAuthClient();
this.FusionAuthApiClient = new FusionAuthApiClient();
}

public invokeAuthenticationFlow(): void {
Expand All @@ -45,10 +49,10 @@ export class AuthenticationSession {
}

private processPasswordResponse([password]: string[]): void {
this.fusionAuthClient.login({
loginId: this.authContext.username,
this.FusionAuthApiClient.login(
this.authContext.username,
password,
}).then((clientResponse) => {
).then((clientResponse) => {
switch (clientResponse.statusCode) {
case FusionAuthStatusCode.Success:
case FusionAuthStatusCode.SuccessButUnregisteredInApp:
Expand Down
67 changes: 65 additions & 2 deletions src/fusionAuth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { FusionAuthClient } from '@fusionauth/typescript-client';
import fetch from 'node-fetch';

export const getFusionAuthClient = (): FusionAuthClient => new FusionAuthClient(
process.env.FUSION_AUTH_KEY ?? '',
Expand All @@ -13,6 +14,68 @@ export interface PartialClientResponse {

export const isPartialClientResponse = (obj: unknown): obj is PartialClientResponse => (
typeof obj === 'object'
&& obj !== null
&& 'exception' in obj
&& obj !== null
&& 'exception' in obj
);

export interface LoginResponse {
token?: string;
refreshToken?: string;
tokenExpirationInstant?: number;
twoFactorId?: string;
methods?: string[];
}

export class ClientResponse<T> {
public statusCode: number;

public response: T;

public exception: Error;

wasSuccessful(): boolean {
return this.statusCode >= 200 && this.statusCode < 300;
}
}

export class FusionAuthApiClient {
private readonly baseUrl: string;

private readonly headers: Record<string, string>;

private readonly applicationId: string = process.env.FUSION_AUTH_APP_ID ?? '';

constructor(apiKey: string = process.env.FUSION_AUTH_KEY ?? '', baseUrl: string = process.env.FUSION_AUTH_HOST ?? '') {
this.baseUrl = baseUrl;
this.headers = {
Authorization: `${apiKey}`,
'Content-Type': 'application/json',
};
}

public async login(loginId: string, password: string, applicationId: string = this.applicationId): Promise<ClientResponse<LoginResponse>> {
return new Promise((resolve, reject) => {
fetch(`${this.baseUrl}/api/login`, {
method: 'POST',
body: JSON.stringify({
loginId,
password,
applicationId,
}),
headers: this.headers,
}).then(async (response) => {
const clientResponse = new ClientResponse<LoginResponse>();
clientResponse.statusCode = response.status;
const responseBody: LoginResponse = await response.json();
if (response.ok) {
clientResponse.response = responseBody;
}
const err: Error = { name: '', message: JSON.stringify(responseBody) };
clientResponse.exception = err;
resolve(clientResponse);
}).catch((err) => {
reject(err);
});
});
}
}

0 comments on commit d0b0d38

Please sign in to comment.