Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/stupid-times-knock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@aws-amplify/backend-auth': patch
---

feat(auth): support custom domain prefix for cognito domain in user pool
5 changes: 1 addition & 4 deletions packages/backend-auth/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,17 +161,14 @@ class AmplifyAuthGenerator implements ConstructContainerEntryGenerator {
loginWith: translateToAuthConstructLoginWith(
this.props.loginWith,
backendSecretResolver,
stableBackendIdentifiers,
),
senders: translateToAuthConstructSenders(
this.props.senders,
this.getInstanceProps,
),
outputStorageStrategy: this.getInstanceProps.outputStorageStrategy,
};
if (authProps.loginWith.externalProviders) {
authProps.loginWith.externalProviders.domainPrefix =
stableBackendIdentifiers.getStableBackendHash();
}

let authConstruct: AmplifyAuth;
try {
Expand Down
66 changes: 66 additions & 0 deletions packages/backend-auth/src/translate_auth_props.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
BackendSecret,
BackendSecretResolver,
ResolvePathResult,
StableBackendIdentifiers,
} from '@aws-amplify/plugin-types';
import { describe, it } from 'node:test';
import { AuthLoginWithFactoryProps } from './types.js';
Expand Down Expand Up @@ -31,6 +32,8 @@ const appleKeyId = 'appleKeyId';
const applePrivateKey = 'applePrivateKey';
const callbackUrls = ['a', 'b'];
const logoutUrls = ['a', 'b'];
const stableBackendHash = 'testStableBackendHash';
const domainPrefix = 'testDomainPrefix';

const testBackendIdentifier: BackendIdentifier = {
namespace: 'testBackendId',
Expand Down Expand Up @@ -68,8 +71,15 @@ class TestBackendSecretResolver implements BackendSecretResolver {
};
}

class TestStableBackendIdentifiers implements StableBackendIdentifiers {
getStableBackendHash = (): string => {
return stableBackendHash;
};
}

void describe('translateToAuthConstructLoginWith', () => {
const backendResolver = new TestBackendSecretResolver();
const stableBackendIdentifiers = new TestStableBackendIdentifiers();

void it('translates with external providers', () => {
const loginWith: AuthLoginWithFactoryProps = {
Expand Down Expand Up @@ -108,6 +118,7 @@ void describe('translateToAuthConstructLoginWith', () => {
const translated = translateToAuthConstructLoginWith(
loginWith,
backendResolver,
stableBackendIdentifiers,
);

const expected: AuthProps['loginWith'] = {
Expand Down Expand Up @@ -140,6 +151,7 @@ void describe('translateToAuthConstructLoginWith', () => {
},
callbackUrls: callbackUrls,
logoutUrls: logoutUrls,
domainPrefix: stableBackendHash,
},
};
assert.deepStrictEqual(translated, expected);
Expand All @@ -157,15 +169,68 @@ void describe('translateToAuthConstructLoginWith', () => {
const translated = translateToAuthConstructLoginWith(
loginWith,
backendResolver,
stableBackendIdentifiers,
);

const expected: AuthProps['loginWith'] = {
phone,
externalProviders: {
callbackUrls: callbackUrls,
logoutUrls: logoutUrls,
domainPrefix: stableBackendHash,
},
};
assert.deepStrictEqual(translated, expected);
});

void it('translates without custom domain prefix', () => {
const loginWith: AuthLoginWithFactoryProps = {
externalProviders: {
callbackUrls: callbackUrls,
logoutUrls: logoutUrls,
},
};

const translated = translateToAuthConstructLoginWith(
loginWith,
backendResolver,
stableBackendIdentifiers,
);

const expected: AuthProps['loginWith'] = {
externalProviders: {
callbackUrls,
logoutUrls,
domainPrefix: stableBackendHash,
},
};

assert.deepStrictEqual(translated, expected);
});

void it('translates with custom domain prefix', () => {
const loginWith: AuthLoginWithFactoryProps = {
externalProviders: {
callbackUrls: callbackUrls,
logoutUrls: logoutUrls,
domainPrefix: domainPrefix,
},
};

const translated = translateToAuthConstructLoginWith(
loginWith,
backendResolver,
stableBackendIdentifiers,
);

const expected: AuthProps['loginWith'] = {
externalProviders: {
callbackUrls,
logoutUrls,
domainPrefix: domainPrefix,
},
};

assert.deepStrictEqual(translated, expected);
});

Expand All @@ -177,6 +242,7 @@ void describe('translateToAuthConstructLoginWith', () => {
const translated = translateToAuthConstructLoginWith(
loginWith,
backendResolver,
stableBackendIdentifiers,
);

const expected: AuthProps['loginWith'] = {
Expand Down
28 changes: 25 additions & 3 deletions packages/backend-auth/src/translate_auth_props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import {
BackendSecretResolver,
ConstructFactoryGetInstanceProps,
StableBackendIdentifiers,
} from '@aws-amplify/plugin-types';
import {
AmazonProviderFactoryProps,
Expand All @@ -26,10 +27,13 @@ import { AmplifyAuthProps } from './factory.js';
* Translate an Auth factory's loginWith to its Auth construct counterpart. Backend secret fields will be resolved
* to an CFN token and map to the required construct type. Note that not all construct secret fields are of sdk
* SecretValue type, many are (wrongly) of type string as well.
*
* The domain prefix will be used if specified, otherwise a default domain prefix will be generated.
*/
export const translateToAuthConstructLoginWith = (
authFactoryLoginWith: AuthLoginWithFactoryProps,
backendSecretResolver: BackendSecretResolver,
stableBackendIdentifiers: StableBackendIdentifiers,
): AuthProps['loginWith'] => {
const result: AuthProps['loginWith'] =
authFactoryLoginWith as AuthProps['loginWith'];
Expand Down Expand Up @@ -82,6 +86,14 @@ export const translateToAuthConstructLoginWith = (
result.externalProviders.google = googleProps;
}

const domainPrefix = translateDomainPrefix(
stableBackendIdentifiers,
externalProviders.domainPrefix,
);
if (domainPrefix) {
result.externalProviders.domainPrefix = domainPrefix;
}

return result;
};
/**
Expand Down Expand Up @@ -159,14 +171,14 @@ const translateAmazonProps = (

const translateAppleProps = (
backendSecretResolver: BackendSecretResolver,
amazonProviderProps?: AppleProviderFactoryProps,
appleProviderProps?: AppleProviderFactoryProps,
): AppleProviderProps | undefined => {
if (!amazonProviderProps) {
if (!appleProviderProps) {
return undefined;
}

const { clientId, teamId, keyId, privateKey, ...noSecretProps } =
amazonProviderProps;
appleProviderProps;
return {
...noSecretProps,
clientId: backendSecretResolver.resolveSecret(clientId).unsafeUnwrap(),
Expand Down Expand Up @@ -236,3 +248,13 @@ const translateGoogleProps = (
clientSecret: backendSecretResolver.resolveSecret(clientSecretValue),
};
};

const translateDomainPrefix = (
stableBackendIdentifiers: StableBackendIdentifiers,
domainPrefix?: string,
): string | undefined => {
if (!domainPrefix) {
return stableBackendIdentifiers.getStableBackendHash();
}
return domainPrefix;
};
7 changes: 1 addition & 6 deletions packages/backend-auth/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,7 @@ export type OidcProviderFactoryProps = Omit<
*/
export type ExternalProviderGeneralFactoryProps = Omit<
ExternalProviderOptions,
| 'signInWithApple'
| 'loginWithAmazon'
| 'facebook'
| 'oidc'
| 'google'
| 'domainPrefix'
'signInWithApple' | 'loginWithAmazon' | 'facebook' | 'oidc' | 'google'
>;

/**
Expand Down