Skip to content

Commit

Permalink
feat: clean up and consolidate AuthClient API between web and node.js…
Browse files Browse the repository at this point in the history
… SDKs

This commit does the following:

* Extend CredentialProvider so that it is possible to use a session
  token with it.  (This mostly just entailed checking to see if the
  endpoint claims exist in the JWT, and if they don't, requiring the
  user to explicitly override them.)
* Refactor the AuthClients to make their constructor require a
  CredentialProvider, like the CacheClient constructor does.  This
  is possible now that we can support session tokens in
  CredentialProvider.  This allows us to remove the extra arguments
  for credentials/endpoints from the signatures for the generate
  and refresh APIs.
* Refactor the auth client integration tests that Ben wrote so that
  they now live in the common-integration-tests package and can be
  used for both the node.js and web SDKs.
* Clean up and complete the implementations of the generate and
  refresh APIs in the web SDK so that they now have parity with the
  node.js SDK and can pass the shared integration tests.

This commit doesn't address any of the new token generation functionality
that we need to complete in order to be able to dynamically generate
tokens for the web SDK; that will be handled in a subsequent commit.
  • Loading branch information
cprice404 committed May 17, 2023
1 parent c508bc6 commit d51dcde
Show file tree
Hide file tree
Showing 25 changed files with 379 additions and 295 deletions.
10 changes: 5 additions & 5 deletions packages/client-sdk-nodejs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@
},
"scripts": {
"prebuild": "eslint . --ext .ts",
"test": "jest --testPathIgnorePatterns auth.test.ts",
"integration-test-auth": "jest -- auth.test.ts",
"unit-test": "jest unit --testPathIgnorePatterns auth.test.ts",
"integration-test": "jest integration --testPathIgnorePatterns auth.test.ts",
"build-and-run-tests": "cd ../common-integration-tests && npm run build && cd - && jest --testPathIgnorePatterns auth.test.ts",
"test": "jest --testPathIgnorePatterns auth-client.test.ts",
"integration-test-auth": "jest auth-client.test.ts",
"unit-test": "jest unit",
"integration-test": "jest integration --testPathIgnorePatterns auth-client.test.ts",
"build-and-run-tests": "cd ../common-integration-tests && npm run build && cd - && jest --testPathIgnorePatterns auth-client.test.ts",
"lint": "eslint . --ext .ts",
"format": "eslint . --ext .ts --fix",
"watch": "tsc -w",
Expand Down
8 changes: 8 additions & 0 deletions packages/client-sdk-nodejs/src/auth-client-props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {CredentialProvider} from '.';

export interface AuthClientProps {
/**
* controls how the client will get authentication information for connecting to the Momento service
*/
credentialProvider: CredentialProvider;
}
22 changes: 6 additions & 16 deletions packages/client-sdk-nodejs/src/auth-client.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {AuthClient as InternalAuthClient} from './internal/auth-client';
import {InternalAuthClient} from './internal/internal-auth-client';
import {IAuthClient} from '@gomomento/sdk-core/dist/src/internal/clients/auth/IAuthClient';
import {AbstractAuthClient} from '@gomomento/sdk-core/dist/src/internal/clients/auth/AbstractAuthClient';
import {
GenerateAuthToken,
ExpiresIn,
CredentialProvider,
RefreshAuthToken,
} from '@gomomento/sdk-core';
import {AuthClientProps} from './auth-client-props';

export class AuthClient extends AbstractAuthClient implements IAuthClient {
constructor() {
const authClient = new InternalAuthClient();
constructor(props: AuthClientProps) {
const authClient = new InternalAuthClient(props);

super({createAuthClient: () => authClient});
}
Expand All @@ -27,15 +27,9 @@ export class AuthClient extends AbstractAuthClient implements IAuthClient {
* {@link GenerateAuthToken.Error} on failure.
*/
public async generateAuthToken(
controlEndpoint: string,
token: string,
expiresIn: ExpiresIn
): Promise<GenerateAuthToken.Response> {
return await this.authClient.generateAuthToken(
controlEndpoint,
token,
expiresIn
);
return await this.authClient.generateAuthToken(expiresIn);
}

/**
Expand All @@ -48,12 +42,8 @@ export class AuthClient extends AbstractAuthClient implements IAuthClient {
* {@link RefreshAuthToken.Error} on failure.
*/
public async refreshAuthToken(
credentialProvider: CredentialProvider,
refreshToken: string
): Promise<RefreshAuthToken.Response> {
return await this.authClient.refreshAuthToken(
credentialProvider,
refreshToken
);
return await this.authClient.refreshAuthToken(refreshToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,34 @@ import {
RefreshAuthToken,
GenerateAuthToken,
} from '@gomomento/sdk-core/dist/src';
import {IAuthClient} from '@gomomento/sdk-core/dist/src/internal/clients';
import {AuthClientProps} from '../auth-client-props';

export class AuthClient {
export class InternalAuthClient implements IAuthClient {
private static readonly REQUEST_TIMEOUT_MS: number = 60 * 1000;

private readonly creds: CredentialProvider;
private readonly interceptors: Interceptor[];

constructor() {
constructor(props: AuthClientProps) {
this.creds = props.credentialProvider;
const headers = [new Header('Agent', `nodejs:${version}`)];
this.interceptors = [
new HeaderInterceptorProvider(headers).createHeadersInterceptor(),
ClientTimeoutInterceptor(AuthClient.REQUEST_TIMEOUT_MS),
ClientTimeoutInterceptor(InternalAuthClient.REQUEST_TIMEOUT_MS),
];
}

public async generateAuthToken(
controlEndpoint: string,
token: string,
expiresIn: ExpiresIn
): Promise<GenerateAuthToken.Response> {
const authClient = new grpcAuth.AuthClient(
controlEndpoint,
this.creds.getControlEndpoint(),
ChannelCredentials.createSsl()
);

const request = new grpcAuth._GenerateApiTokenRequest({
session_token: token,
session_token: this.creds.getAuthToken(),
});

if (expiresIn.doesExpire()) {
Expand Down Expand Up @@ -81,16 +83,15 @@ export class AuthClient {
}

public async refreshAuthToken(
credentialProvider: CredentialProvider,
refreshToken: string
): Promise<RefreshAuthToken.Response> {
const authClient = new grpcAuth.AuthClient(
credentialProvider.getControlEndpoint(),
this.creds.getControlEndpoint(),
ChannelCredentials.createSsl()
);

const request = new grpcAuth._RefreshApiTokenRequest({
api_key: credentialProvider.getAuthToken(),
api_key: this.creds.getAuthToken(),
refresh_token: refreshToken,
});

Expand Down
116 changes: 0 additions & 116 deletions packages/client-sdk-nodejs/test/integration/auth.test.ts

This file was deleted.

35 changes: 19 additions & 16 deletions packages/client-sdk-nodejs/test/integration/integration-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@ function momentoClientForTesting(): CacheClient {
return new CacheClient(IntegrationTestCacheClientProps);
}

function momentoAuthClientForTesting(): AuthClient {
return new AuthClient();
}

function momentoTopicClientForTesting(): TopicClient {
return new TopicClient({
configuration: IntegrationTestCacheClientProps.configuration,
Expand Down Expand Up @@ -98,20 +94,27 @@ export function SetupTopicIntegrationTest(): {
return {topicClient, Momento, IntegrationTestCacheName};
}

export function SetupAuthIntegrationTest(): {
authClient: AuthClient;
sessionToken: string;
controlEndpoint: string;
export function SetupAuthClientIntegrationTest(): {
sessionTokenAuthClient: AuthClient;
authTokenAuthClientFactory: (authToken: string) => AuthClient;
} {
const sessionToken = process.env.TEST_SESSION_TOKEN;
if (sessionToken === undefined) {
throw new Error('Missing required env var TEST_SESSION_TOKEN');
}

return {
authClient: momentoAuthClientForTesting(),
sessionToken: sessionToken,
controlEndpoint: credsProvider.getControlEndpoint(),
sessionTokenAuthClient: new AuthClient({
credentialProvider: CredentialProvider.fromEnvironmentVariable({
environmentVariableName: 'TEST_SESSION_TOKEN',
// session tokens don't include cache/control endpoints, so we must provide them. In this case we just hackily
// steal them from the auth-token-based creds provider.
cacheEndpoint: credsProvider.getCacheEndpoint(),
controlEndpoint: credsProvider.getControlEndpoint(),
}),
}),
authTokenAuthClientFactory: authToken => {
return new AuthClient({
credentialProvider: CredentialProvider.fromString({
authToken: authToken,
}),
});
},
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {SetupAuthClientIntegrationTest} from '../integration-setup';
import {runAuthClientTests} from '@gomomento/common-integration-tests';

const {sessionTokenAuthClient, authTokenAuthClientFactory} =
SetupAuthClientIntegrationTest();

runAuthClientTests(sessionTokenAuthClient, authTokenAuthClientFactory);
7 changes: 4 additions & 3 deletions packages/client-sdk-web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@
},
"scripts": {
"prebuild": "eslint . --ext .ts",
"test": "jest",
"test": "jest --testPathIgnorePatterns auth-client.test.ts",
"unit-test": "jest unit",
"integration-test": "jest integration",
"build-and-run-tests": "cd ../common-integration-tests && npm run build && cd - && jest",
"integration-test-auth": "jest auth-client.test.ts",
"integration-test": "jest integration --testPathIgnorePatterns auth-client.test.ts",
"build-and-run-tests": "cd ../common-integration-tests && npm run build && cd - && jest --testPathIgnorePatterns auth-client.test.ts",
"lint": "eslint . --ext .ts",
"format": "eslint . --ext .ts --fix",
"watch": "tsc -w",
Expand Down
8 changes: 8 additions & 0 deletions packages/client-sdk-web/src/auth-client-props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {CredentialProvider} from '.';

export interface AuthClientProps {
/**
* controls how the client will get authentication information for connecting to the Momento service
*/
credentialProvider: CredentialProvider;
}
5 changes: 3 additions & 2 deletions packages/client-sdk-web/src/auth-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import {
IAuthClient,
} from '@gomomento/sdk-core/dist/src/internal/clients/index';
import {InternalWebGrpcAuthClient} from './internal/auth-client';
import {AuthClientProps} from './auth-client-props';

export class AuthClient extends AbstractAuthClient {
constructor() {
constructor(props: AuthClientProps) {
const createAuthClient = (): IAuthClient => {
return new InternalWebGrpcAuthClient();
return new InternalWebGrpcAuthClient(props);
};
super({createAuthClient});
}
Expand Down
Loading

0 comments on commit d51dcde

Please sign in to comment.