Skip to content

Commit 38dab98

Browse files
authored
fix(amplify-provider-awscloudformation): admin token refresh, configure project (#6629)
1 parent c1366d1 commit 38dab98

File tree

4 files changed

+52
-42
lines changed

4 files changed

+52
-42
lines changed

packages/amplify-provider-awscloudformation/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,6 @@
106106
"moment": "^2.24.0",
107107
"netmask": "^1.0.6",
108108
"node-fetch": "^2.6.1",
109-
"open": "^7.0.0",
110109
"ora": "^4.0.3",
111110
"promise-sequential": "^1.1.1",
112111
"proxy-agent": "^3.1.1",

packages/amplify-provider-awscloudformation/src/admin-login.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import open from 'open';
21
import ora from 'ora';
3-
import { $TSContext } from 'amplify-cli-core';
2+
import { $TSContext, open } from 'amplify-cli-core';
43

54
import { adminVerifyUrl, adminBackendMap, isAmplifyAdminApp } from './utils/admin-helpers';
65
import { AdminLoginServer } from './utils/admin-login-server';
76

8-
export async function adminLoginFlow(context: $TSContext, appId: string, envName: string, region?: string) {
7+
export async function adminLoginFlow(context: $TSContext, appId: string, envName?: string, region?: string) {
8+
envName = envName || context.amplify.getEnvInfo().envName;
99
if (!region) {
1010
const { isAdminApp, region: _region } = await isAmplifyAdminApp(appId);
1111
if (!isAdminApp) {

packages/amplify-provider-awscloudformation/src/configuration-manager.ts

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { prompt } from 'inquirer';
55
import _ from 'lodash';
66
import path from 'path';
77
import proxyAgent from 'proxy-agent';
8-
import { adminLoginFlow } from './admin-login';
98
import awsRegions from './aws-regions';
109
import constants from './constants';
1110
import setupNewUser from './setup-new-user';
@@ -346,13 +345,29 @@ async function promptForAuthConfig(context: $TSContext, authConfig?: AuthFlowCon
346345
let answers: $TSAny;
347346

348347
if (availableProfiles && availableProfiles.length > 0) {
349-
const authType = authConfig.type ?? (await askAuthType());
348+
let authType: AuthFlow;
349+
let isAdminApp = false;
350+
if (authConfig?.type) {
351+
authType = authConfig.type;
352+
} else {
353+
try {
354+
const appId = resolveAppId(context);
355+
isAdminApp = (await isAmplifyAdminApp(appId))?.isAdminApp || false;
356+
} catch {
357+
isAdminApp = false;
358+
}
359+
authType = await askAuthType(isAdminApp);
360+
}
350361
if (authType === 'profile') {
351362
printProfileInfo(context);
352363
awsConfigInfo.config.useProfile = true;
353364
answers = await prompt(profileNameQuestion(availableProfiles, awsConfigInfo.config.profileName));
354365
awsConfigInfo.config.profileName = answers.profileName;
355366
return;
367+
} else if (authType === 'admin') {
368+
awsConfigInfo.configLevel = 'amplifyAdmin';
369+
awsConfigInfo.config.useProfile = false;
370+
return;
356371
}
357372
} else {
358373
awsConfigInfo.config.useProfile = false;
@@ -547,20 +562,16 @@ export async function loadConfigurationForEnv(context: $TSContext, env: string,
547562

548563
const projectConfigInfo = getConfigForEnv(context, env);
549564
const authType = await determineAuthFlow(context, projectConfigInfo);
550-
const { print, usageData } = context;
551565
let awsConfig: AwsSdkConfig;
552566

553567
if (authType.type === 'admin') {
554568
projectConfigInfo.configLevel = 'amplifyAdmin';
555569
appId = appId || authType.appId;
556-
if (!doAdminTokensExist(appId)) {
557-
adminLoginFlow(context, appId, env, authType.region);
558-
}
559570
try {
560-
awsConfig = await getTempCredsWithAdminTokens(appId, print);
561-
} catch (error) {
562-
print.error(`Failed to get credentials: ${error.message || error}`);
563-
await usageData.emitError(error);
571+
awsConfig = await getTempCredsWithAdminTokens(context, appId);
572+
} catch (e) {
573+
context.print.error(`Failed to get credentials: ${e.message || e}`);
574+
await context.usageData.emitError(e);
564575
exitOnNextTick(1);
565576
}
566577
} else if (authType.type === 'profile') {
@@ -698,12 +709,8 @@ export async function getAwsConfig(context: $TSContext): Promise<AwsConfig> {
698709
}
699710
} else if (awsConfigInfo.configLevel === 'amplifyAdmin') {
700711
const appId = resolveAppId(context);
701-
702-
if (!doAdminTokensExist(appId)) {
703-
await adminLoginFlow(context, appId, context.amplify.getEnvInfo().envName);
704-
}
705712
try {
706-
awsConfig = await getTempCredsWithAdminTokens(appId, context.print);
713+
awsConfig = await getTempCredsWithAdminTokens(context, appId);
707714
} catch (err) {
708715
context.print.error('Failed to fetch Amplify Admin credentials');
709716
throw new Error(err);

packages/amplify-provider-awscloudformation/src/utils/admin-helpers.ts

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { stateManager, $TSContext } from 'amplify-cli-core';
22
import aws from 'aws-sdk';
33
import _ from 'lodash';
44
import fetch from 'node-fetch';
5+
import { adminLoginFlow } from '../admin-login';
56
import { AdminAuthConfig, AwsSdkConfig, CognitoAccessToken, CognitoIdToken } from './auth-types';
67

78
export const adminVerifyUrl = (appId: string, envName: string, region: string): string => {
@@ -27,8 +28,11 @@ export async function isAmplifyAdminApp(appId: string): Promise<{ isAdminApp: bo
2728
return { isAdminApp: !!appState.appId, region: appState.region };
2829
}
2930

30-
export async function getTempCredsWithAdminTokens(appId: string, print: $TSContext['print']): Promise<AwsSdkConfig> {
31-
const authConfig = await getRefreshedTokens(appId, print);
31+
export async function getTempCredsWithAdminTokens(context: $TSContext, appId: string): Promise<AwsSdkConfig> {
32+
if (!doAdminTokensExist(appId)) {
33+
await adminLoginFlow(context, appId);
34+
}
35+
const authConfig = await getRefreshedTokens(context, appId);
3236
const { idToken, IdentityId, region } = authConfig;
3337
// use tokens to get creds and assign to config
3438
const awsConfig = await getAdminCognitoCredentials(idToken, IdentityId, region);
@@ -82,17 +86,23 @@ async function getAdminStsCredentials(idToken: CognitoIdToken, region: string):
8286
};
8387
}
8488

85-
export async function getRefreshedTokens(appId: string, print: $TSContext['print']) {
89+
async function getRefreshedTokens(context: $TSContext, appId: string) {
8690
// load token, check expiry, refresh if needed
8791
const authConfig: AdminAuthConfig = stateManager.getAmplifyAdminConfigEntry(appId);
8892

8993
if (isJwtExpired(authConfig.idToken)) {
90-
const refreshedTokens = await refreshJWTs(authConfig, print);
91-
// Refresh stored tokens
92-
authConfig.accessToken.jwtToken = refreshedTokens.AccessToken;
93-
authConfig.idToken.jwtToken = refreshedTokens.IdToken;
94-
authConfig.refreshToken.token = refreshedTokens.RefreshToken;
95-
stateManager.setAmplifyAdminConfigEntry(appId, authConfig);
94+
let refreshedTokens: aws.CognitoIdentityServiceProvider.AuthenticationResultType;
95+
try {
96+
refreshedTokens = (await refreshJWTs(authConfig)).AuthenticationResult;
97+
// Refresh stored tokens
98+
authConfig.accessToken.jwtToken = refreshedTokens.AccessToken;
99+
authConfig.idToken.jwtToken = refreshedTokens.IdToken;
100+
authConfig.refreshToken.token = refreshedTokens.RefreshToken;
101+
stateManager.setAmplifyAdminConfigEntry(appId, authConfig);
102+
} catch {
103+
// Refresh failed, fall back to login
104+
await adminLoginFlow(context, appId, null, authConfig.region);
105+
}
96106
}
97107
return authConfig;
98108
}
@@ -103,21 +113,15 @@ function isJwtExpired(token: CognitoAccessToken | CognitoIdToken) {
103113
return secSinceEpoch >= expiration - 60;
104114
}
105115

106-
async function refreshJWTs(authConfig: AdminAuthConfig, print: $TSContext['print']) {
116+
async function refreshJWTs(authConfig: AdminAuthConfig) {
107117
const CognitoISP = new aws.CognitoIdentityServiceProvider({ region: authConfig.region });
108-
try {
109-
const result = await CognitoISP.initiateAuth({
110-
AuthFlow: 'REFRESH_TOKEN',
111-
AuthParameters: {
112-
REFRESH_TOKEN: authConfig.refreshToken.token,
113-
},
114-
ClientId: authConfig.accessToken.payload.client_id, // App client id from identityPool
115-
}).promise();
116-
return result.AuthenticationResult;
117-
} catch (e) {
118-
print.error(`Failed to refresh tokens: ${e.message || 'Unknown error occurred'}`);
119-
throw e;
120-
}
118+
return await CognitoISP.initiateAuth({
119+
AuthFlow: 'REFRESH_TOKEN',
120+
AuthParameters: {
121+
REFRESH_TOKEN: authConfig.refreshToken.token,
122+
},
123+
ClientId: authConfig.accessToken.payload.client_id, // App client id from identityPool
124+
}).promise();
121125
}
122126

123127
export const adminBackendMap: {

0 commit comments

Comments
 (0)