Skip to content

feat(cognito-idp): make TOTP MFA work - #9785

Merged
bblommers merged 3 commits into
getmoto:masterfrom
bdellegrazie:feat/cognito-totp
Mar 16, 2026
Merged

feat(cognito-idp): make TOTP MFA work#9785
bblommers merged 3 commits into
getmoto:masterfrom
bdellegrazie:feat/cognito-totp

Conversation

@bdellegrazie

@bdellegrazie bdellegrazie commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

Implement TOTP MFA using the existing cryptography API. This allows clients to behave correctly and use proper TOTP validation compared with previously where the UserCode was not handled.

Warning: this implementation still uses the fixed constant "secret" and therefore should not be considered for anything other than testing.

A solution implementing "real" TOTP was considered but would need storing the secret temporarily in the session during the auth process but the session object is unfortunately a tuple at this time.

Closes #9786

@bdellegrazie
bdellegrazie force-pushed the feat/cognito-totp branch 2 times, most recently from 2acb0b8 to 6e1fb23 Compare February 25, 2026 15:22
@codecov

codecov Bot commented Feb 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.74359% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 93.12%. Comparing base (b6e48f1) to head (a37d6d7).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
moto/cognitoidp/models.py 83.33% 4 Missing ⚠️

❌ Your patch status has failed because the patch coverage (89.74%) is below the target coverage (90.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #9785      +/-   ##
==========================================
- Coverage   93.12%   93.12%   -0.01%     
==========================================
  Files        1314     1314              
  Lines      119183   119217      +34     
==========================================
+ Hits       110991   111022      +31     
- Misses       8192     8195       +3     
Flag Coverage Δ
servertests 29.16% <43.58%> (+<0.01%) ⬆️
unittests 93.10% <89.74%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bdellegrazie
bdellegrazie force-pushed the feat/cognito-totp branch 2 times, most recently from 04ee252 to 16859cf Compare February 26, 2026 11:45
@bdellegrazie

Copy link
Copy Markdown
Contributor Author

Added a test for the cognito_totp utility and rebased on master

@bblommers bblommers left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @bdellegrazie! I imagine that the majority of people will not go through the trouble of setting up TOTP in their tests, and will just use a random UserCode on verification. That is a valid test strategy, as far a I'm concerned.

I do see the benefit of this feature, though - can we hide it behind a feature flag? We typically use environment variables for these usecases, so in this case we could use: MOTO_COGNITO_ENABLE_TOTP=true.

Only if that env variable is set would Moto validate the provided UserCode - if not, Moto accepts everything.

I would also like to see a negative test: what happens when the user provides an invalid user code (with this env var enabled)? How does AWS behave when providing an invalid code?

@bdellegrazie
bdellegrazie force-pushed the feat/cognito-totp branch 2 times, most recently from 348e15f to 12f041f Compare March 1, 2026 19:11
@bdellegrazie
bdellegrazie requested a review from bblommers March 1, 2026 19:12
@bdellegrazie

bdellegrazie commented Mar 1, 2026

Copy link
Copy Markdown
Contributor Author

Hi @bblommers,

Thanks for the review!

  • I've used MOTO_COGNITO_IDP_USER_POOL_ENABLE_TOTP to match the existing Cognito feature flags, happy to change it if you would prefer.
  • Added negative test as requested
  • Added additional positive test when the feature is "masked" (i.e. not enabled) - this the same as the original _enabled test which has been converted to the real TOTP enabled test. I can change it to _disabled if you prefer but that may be confusing given TOTP is enabled, just it's verification is bypassed.
  • Fixed missing behaviour in respond_to_auth_challenge where the TOTP token wasn't being checked at all.
  • Made the totp secret a static constant (for the moment)

@bdellegrazie
bdellegrazie force-pushed the feat/cognito-totp branch 4 times, most recently from 9496ca7 to 5b32839 Compare March 5, 2026 09:13
@bdellegrazie
bdellegrazie force-pushed the feat/cognito-totp branch 2 times, most recently from 7408e4d to 62bd97f Compare March 9, 2026 11:58
@bdellegrazie

bdellegrazie commented Mar 9, 2026

Copy link
Copy Markdown
Contributor Author

@bblommers could you please re-review?

I had to delete the test which verifies the old behaviour (TOTP code of anything) because it doesn't work ServerSide.
If there's a marker which can exclude a test specifically on a server-side run, that would help.

@bblommers

Copy link
Copy Markdown
Collaborator

Hi @bdellegrazie! There is no marker, but we typically just add an if-statement to the top of the test:

from unittest import SkipTest

from moto import mock_aws, settings

def test():
    if not settings.TEST_DECORATOR_MODE:
        raise SkipTest("Can only change setting in DecoratorMode")

Everything else LGTM, so if we can keep the test to verify the old behaviour, I'd be happy to merge.

Implement TOTP MFA using the existing cryptography API.
This allows clients to behave correctly and use proper TOTP validation
compared with previously where the UserCode was not handled.

Warning: this implementation still uses the fixed constant "secret" and
therefore should not be considered for anything other than testing.

A solution implementing "real" TOTP was considered but would need
storing the secret temporarily in the session during the auth process
but the session object is unfortunately a tuple at this time.
* Put working TOTP MFA behind a feature flag - specifically
`MOTO_COGNITO_IDP_USER_POOL_ENABLE_TOTP`
* Support the FriendlyDeviceName field, although only for error
  reporting to end-user
@bdellegrazie

Copy link
Copy Markdown
Contributor Author

@bblommers I've added the additional negative test. Anything else?

@bblommers bblommers left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - thank you so much for adding this feature to Moto @bdellegrazie!

@bblommers bblommers added this to the 5.2 milestone Mar 16, 2026
@bblommers
bblommers merged commit 700cf1f into getmoto:master Mar 16, 2026
70 of 71 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Cognito MFA TOTP support

2 participants