Skip to content

Commit

Permalink
chore: add credential provider
Browse files Browse the repository at this point in the history
  • Loading branch information
tiwarishubham635 committed Nov 14, 2024
1 parent 1728c0c commit f6a4901
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 22 deletions.
74 changes: 52 additions & 22 deletions src/base/BaseTwilio.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import RequestClient from "./RequestClient"; /* jshint ignore:line */
import { HttpMethod } from "../interfaces"; /* jshint ignore:line */
import { Headers } from "../http/request"; /* jshint ignore:line */
import AuthStrategy from "../auth_strategy/AuthStrategy"; /* jshint ignore:line */
import CredentialProvider from "../credential_provider/CredentialProvider"; /* jshint ignore:line */

This comment has been minimized.

Copy link
@Alishaolver

Alishaolver Nov 30, 2024

src/base/BaseTwilio.ts


const os = require("os"); /* jshint ignore:line */
const url = require("url"); /* jshint ignore:line */
Expand Down Expand Up @@ -40,6 +42,7 @@ namespace Twilio {
uri?: string;
username?: string;
password?: string;
authStrategy?: AuthStrategy;
headers?: Headers;
params?: object;
data?: object;
Expand All @@ -56,9 +59,10 @@ namespace Twilio {
/* jshint ignore:end */

export class Client {
username: string;
password: string;
accountSid: string;
username?: string;
password?: string;
accountSid?: string;
credentialProvider?: CredentialProvider;
opts?: ClientOpts;
env?: NodeJS.ProcessEnv;
edge?: string;
Expand Down Expand Up @@ -101,23 +105,28 @@ namespace Twilio {
/* jshint ignore:end */

constructor(username?: string, password?: string, opts?: ClientOpts) {
this.opts = opts || {};
this.env = this.opts.env || {};
this.setOpts(opts);
this.username =
username ??
this.env.TWILIO_ACCOUNT_SID ??
process.env.TWILIO_ACCOUNT_SID ??
(() => {
throw new Error("username is required");
})();
username ??
this.env?.TWILIO_ACCOUNT_SID ??
process.env.TWILIO_ACCOUNT_SID ??
(() => {
throw new Error("username is required");
})();
this.password =
password ??
this.env.TWILIO_AUTH_TOKEN ??
process.env.TWILIO_AUTH_TOKEN ??
(() => {
throw new Error("password is required");
})();
this.accountSid = this.opts.accountSid || this.username;
password ??
this.env?.TWILIO_AUTH_TOKEN ??
process.env.TWILIO_AUTH_TOKEN ??
(() => {
throw new Error("password is required");
})();
this.setAccountSid(this.opts?.accountSid || this.username);
this.invalidateOAuth();
}

setOpts(opts?: ClientOpts) {
this.opts = opts || {};
this.env = this.opts.env || {};
this.edge =
this.opts.edge ?? this.env.TWILIO_EDGE ?? process.env.TWILIO_EDGE;
this.region =
Expand All @@ -144,16 +153,35 @@ namespace Twilio {
if (this.opts.lazyLoading === false) {
this._httpClient = this.httpClient;
}
}

setAccountSid(accountSid: string) {
this.accountSid = accountSid;

if (!this.accountSid.startsWith("AC")) {
const apiKeyMsg = this.accountSid.startsWith("SK")
? ". The given SID indicates an API Key which requires the accountSid to be passed as an additional option"
: "";
if (this.accountSid && !this.accountSid?.startsWith("AC")) {
const apiKeyMsg = this.accountSid?.startsWith("SK")
? ". The given SID indicates an API Key which requires the accountSid to be passed as an additional option"
: "";

throw new Error("accountSid must start with AC" + apiKeyMsg);
}
}

setCredentialProvider(credentialProvider: CredentialProvider) {
this.credentialProvider = credentialProvider;
this.accountSid = undefined;
this.invalidateBasicAuth();
}

invalidateBasicAuth() {
this.username = undefined;
this.password = undefined;
}

invalidateOAuth() {
this.credentialProvider = undefined;
}

get httpClient() {
if (!this._httpClient) {
this._httpClient = new RequestClient({
Expand Down Expand Up @@ -196,6 +224,7 @@ namespace Twilio {

const username = opts.username || this.username;
const password = opts.password || this.password;
const authStrategy = opts.authStrategy || this.credentialProvider?.toAuthStrategy();

const headers = opts.headers || {};

Expand Down Expand Up @@ -235,6 +264,7 @@ namespace Twilio {
uri: uri.href,
username: username,
password: password,
authStrategy: authStrategy,
headers: headers,
params: opts.params,
data: opts.data,
Expand Down
4 changes: 4 additions & 0 deletions src/base/RequestClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Request, {
RequestOptions as LastRequestOptions,
Headers,
} from "../http/request";
import AuthStrategy from "../auth_strategy/AuthStrategy";

const DEFAULT_CONTENT_TYPE = "application/x-www-form-urlencoded";
const DEFAULT_TIMEOUT = 30000;
Expand Down Expand Up @@ -180,6 +181,8 @@ class RequestClient {
"base64"
);
headers.Authorization = "Basic " + auth;
} else if(opts.authStrategy) {
headers.Authorization = opts.authStrategy.getAuthString();
}

const options: AxiosRequestConfig = {
Expand Down Expand Up @@ -296,6 +299,7 @@ namespace RequestClient {
* The password used for auth
*/
password?: string;
authStrategy?: AuthStrategy;
/**
* The request headers
*/
Expand Down
64 changes: 64 additions & 0 deletions src/credential_provider/ClientCredentialProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import CredentialProvider from "./CredentialProvider";
import TokenManager from "../http/bearer_token/TokenManager";
import AuthStrategy from "../auth_strategy/AuthStrategy";
import ApiTokenManager from "../http/bearer_token/ApiTokenManager";
import TokenAuthStrategy from "../auth_strategy/TokenAuthStrategy";

class ClientCredentialProvider extends CredentialProvider {
grantType: string;
clientId: string;
clientSecret: string;
tokenManager: TokenManager | null;

constructor() {
super("client-credentials");
this.grantType = "client_credentials";
this.clientId = "";
this.clientSecret = "";
this.tokenManager = null;
}

public toAuthStrategy(): AuthStrategy {
if (this.tokenManager == null) {
this.tokenManager = new ApiTokenManager({
grantType: this.grantType,
clientId: this.clientId,
clientSecret: this.clientSecret,
});
}
return new TokenAuthStrategy(this.tokenManager);
}
}

namespace ClientCredentialProvider {
export class ClientCredentialProviderBuilder {
private readonly instance: ClientCredentialProvider;

constructor() {
this.instance = new ClientCredentialProvider();
}

public setClientId(clientId: string): ClientCredentialProviderBuilder {
this.instance.clientId = clientId;
return this;
}

public setClientSecret(clientSecret: string): ClientCredentialProviderBuilder {
this.instance.clientSecret = clientSecret;
return this;
}

public setTokenManager(tokenManager: TokenManager): ClientCredentialProviderBuilder {
this.instance.tokenManager = tokenManager;
return this;
}

public build(): ClientCredentialProvider {
return this.instance;
}
}
}

export = ClientCredentialProvider;


9 changes: 9 additions & 0 deletions src/credential_provider/CredentialProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import AuthStrategy from "../auth_strategy/AuthStrategy";

export default abstract class CredentialProvider {
private authType: string;
protected constructor(authType: string) {
this.authType = authType;
}
abstract toAuthStrategy(): AuthStrategy;
}
13 changes: 13 additions & 0 deletions src/credential_provider/NoAuthCredentialProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import CredentialProvider from "./CredentialProvider";
import AuthStrategy from "../auth_strategy/AuthStrategy";
import NoAuthStrategy from "../auth_strategy/NoAuthStrategy";

export default class NoAuthCredentialProvider extends CredentialProvider {
constructor() {
super("client-credentials");
}

public toAuthStrategy(): AuthStrategy {
return new NoAuthStrategy();
}
}
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as taskRouterUtil from "./jwt/taskrouter/util";
import IVoiceResponse from "./twiml/VoiceResponse";
import IMessagingResponse from "./twiml/MessagingResponse";
import IFaxResponse from "./twiml/FaxResponse";
import IClientCredentialProvider from "./credential_provider/ClientCredentialProvider";

// Shorthand to automatically create a RestClient
function TwilioSDK(
Expand Down Expand Up @@ -44,6 +45,10 @@ namespace TwilioSDK {
}
export type RequestClient = IRequestClient;
export const RequestClient = IRequestClient;

export type ClientCredentialProviderBuilder = IClientCredentialProvider.ClientCredentialProviderBuilder;
export const ClientCredentialProviderBuilder = IClientCredentialProvider.ClientCredentialProviderBuilder;

// Setup webhook helper functionality
export type validateBody = typeof webhooks.validateBody;
export const validateBody = webhooks.validateBody;
Expand Down

0 comments on commit f6a4901

Please sign in to comment.