aws-amplify / aws-amplify/amplify-cli
MFA role assumption fails with "Resolved credential object is not valid" after v14.2.2
- Dominant language
- TypeScript
- Stars
- 2.9k
- Forks
- 825
- Avg merge
- 11d 23h
- Merged PRs (30d)
- 2
Description
## How did you install the Amplify CLI?
npm
## What version of Node.js are you using?
v24.11.1
## What version of Amplify CLI are you using?
14.2.5 (regression introduced in v14.2.2 by PR #14315, still present as of 14.2.5)
## What operating system are you using?
macOS
## Did you make any manual changes to the cloud resources managed by Amplify? Please describe the changes if any.
No
## Describe the bug
Three cascading bugs in the MFA role assumption credential caching logic were introduced by commit `04f7bcfc24` (PR #14315, fixing #14290 "role assumption through profiles not working properly"). These bugs cause MFA-based role assumption to fail with the error `Resolved credential object is not valid`.
### Bug 1: MFA prompt never appears
`getCachedRoleCredentials()` always returns an object `{ credentials: {} }` even when no valid cached credentials exist. This causes the check `if (!roleCredentials)` in `getRoleCredentials()` to always be false, so the STS `AssumeRole` call with MFA token is never executed.
### Bug 2: Credential cache validation always fails
Credentials are cached in nested format `{ credentials: { accessKeyId, ... } }` but `validateCachedCredentials()` expects flat format `{ accessKeyId, ... }`. This causes cache validation to always fail, prompting for MFA on every CLI call.
### Bug 3: `identity.expiration.getTime is not a function` error
When credentials are read from the JSON cache file, the `Date` object for `expiration` is deserialized as a string. The AWS SDK's `@smithy/core` module calls `expiration.getTime()` which fails on a string.
The fix in PR #14315 only addressed this in `getConfiguredAWSClientConfig()`, but `getProfiledAwsConfig()` is called directly during `amplify env checkout` without going through that code path.
## Expected behavior
1. When no valid cached MFA credentials exist, the user is prompted for their MFA token
2. After successful role assumption, credentials are cached and reused until they expire
3. Cached credentials are correctly deserialized (including `expiration` as a `Date` object)
## Reproduction steps
1. Configure an AWS profile with `role_arn` + `source_profile` + `mfa_serial`
2. Run `amplify env checkout ` with CLI version 14.2.2 or later
3. Observe the error `Resolved credential object is not valid` — no MFA prompt appears
## Log output
```
Resolved credential object is not valid
```
## Additional information
This is a regression from PR #14315 (fixing #14290). The three bugs cascade — fixing Bug 1 alone surfaces Bug 2, and fixing Bug 2 alone surfaces Bug 3.
**Affected file:** `packages/amplify-provider-awscloudformation/src/system-config-manager.ts`
**Fixes:**
1. Return `undefined` from `getCachedRoleCredentials()` when no valid cached credentials exist
2. Cache the flat credentials object (`roleCredentials.credentials`) instead of the nested wrapper
3. Convert `expiration` from string to `Date` when returning cached credentials
Contributor guide
Research direction
Start in packages/amplify-provider-awscloudformation/src/system-config-manager.ts and trace getCachedRoleCredentials(), validateCachedCredentials(), getRoleCredentials(), and getProfiledAwsConfig() during amplify env checkout. Reproduce with an AWS profile using role_arn, source_profile, and mfa_serial; done means MFA is requested when needed, valid cached credentials are reused, and cached expiration is returned as a Date.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- authentication, cli, cloud
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100