Amplify V6 -- signin and confirmsignin cannot work separatly?
Before opening, please confirm:
- [X] I have searched for duplicate or closed issues and discussions.
- [X] I have read the guide for submitting bug reports.
- [X] I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
JavaScript Framework
Next.js
Amplify APIs
Authentication
Amplify Version
v6
Amplify Categories
auth
Backend
Other
Environment information
# Put output below this line
System:
OS: macOS 14.4
CPU: (8) arm64 Apple M1
Memory: 70.72 MB / 8.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.10.0 - ~/.nvm/versions/node/v20.10.0/bin/node
npm: 10.2.3 - ~/.nvm/versions/node/v20.10.0/bin/npm
Browsers:
Chrome: 123.0.6312.59
Safari: 17.4
npmPackages:
@ampproject/toolbox-optimizer: undefined ()
@aws-amplify/adapter-nextjs: ^1.0.21 => 1.0.21
@aws-amplify/adapter-nextjs/api: undefined ()
@aws-amplify/adapter-nextjs/data: undefined ()
@aws-sdk/client-cognito-identity: ^3.540.0 => 3.540.0
@aws-sdk/client-cognito-identity-provider: ^3.540.0 => 3.540.0
@babel/core: undefined ()
@babel/runtime: 7.22.5
@edge-runtime/cookies: 4.1.0
@edge-runtime/ponyfill: 2.4.2
@edge-runtime/primitives: 4.1.0
@hapi/accept: undefined ()
@mswjs/interceptors: undefined ()
@napi-rs/triples: undefined ()
@next/font: undefined ()
@next/react-dev-overlay: undefined ()
@opentelemetry/api: undefined ()
@types/node: ^20 => 20.11.30
@types/react: ^18 => 18.2.67
@types/react-dom: ^18 => 18.2.22
@vercel/nft: undefined ()
@vercel/og: 0.6.2
acorn: undefined ()
amphtml-validator: undefined ()
anser: undefined ()
arg: undefined ()
assert: undefined ()
async-retry: undefined ()
async-sema: undefined ()
autoprefixer: ^10.0.1 => 10.4.19
aws-amplify: ^6.0.21 => 6.0.21
aws-amplify/adapter-core: undefined ()
aws-amplify/analytics: undefined ()
aws-amplify/analytics/kinesis: undefined ()
aws-amplify/analytics/kinesis-firehose: undefined ()
aws-amplify/analytics/personalize: undefined ()
aws-amplify/analytics/pinpoint: undefined ()
aws-amplify/api: undefined ()
aws-amplify/api/server: undefined ()
aws-amplify/auth: undefined ()
aws-amplify/auth/cognito: undefined ()
aws-amplify/auth/cognito/server: undefined ()
aws-amplify/auth/enable-oauth-listener: undefined ()
aws-amplify/auth/server: undefined ()
aws-amplify/data: undefined ()
aws-amplify/data/server: undefined ()
aws-amplify/datastore: undefined ()
aws-amplify/in-app-messaging: undefined ()
aws-amplify/in-app-messaging/pinpoint: undefined ()
aws-amplify/push-notifications: undefined ()
aws-amplify/push-notifications/pinpoint: undefined ()
aws-amplify/storage: undefined ()
aws-amplify/storage/s3: undefined ()
aws-amplify/storage/s3/server: undefined ()
aws-amplify/storage/server: undefined ()
aws-amplify/utils: undefined ()
babel-packages: undefined ()
browserify-zlib: undefined ()
browserslist: undefined ()
buffer: undefined ()
bytes: undefined ()
ci-info: undefined ()
cli-select: undefined ()
client-only: 0.0.1
comment-json: undefined ()
compression: undefined ()
conf: undefined ()
constants-browserify: undefined ()
content-disposition: undefined ()
content-type: undefined ()
cookie: undefined ()
cross-spawn: undefined ()
crypto-browserify: undefined ()
css.escape: undefined ()
data-uri-to-buffer: undefined ()
debug: undefined ()
devalue: undefined ()
domain-browser: undefined ()
dotenv: ^16.4.5 => 16.4.5
edge-runtime: undefined ()
eslint: ^8.57.0 => 8.57.0
eslint-config-next: 14.1.4 => 14.1.4
eslint-config-prettier: ^9.1.0 => 9.1.0
events: undefined ()
find-cache-dir: undefined ()
find-up: undefined ()
fresh: undefined ()
get-orientation: undefined ()
glob: undefined ()
gzip-size: undefined ()
http-proxy: undefined ()
http-proxy-agent: undefined ()
https-browserify: undefined ()
https-proxy-agent: undefined ()
icss-utils: undefined ()
ignore-loader: undefined ()
image-size: undefined ()
is-animated: undefined ()
is-docker: undefined ()
is-wsl: undefined ()
jest-worker: undefined ()
json5: undefined ()
jsonwebtoken: undefined ()
loader-runner: undefined ()
loader-utils: undefined ()
lodash.curry: undefined ()
lru-cache: undefined ()
micromatch: undefined ()
mini-css-extract-plugin: undefined ()
nanoid: undefined ()
native-url: undefined ()
neo-async: undefined ()
next: 14.1.4 => 14.1.4
next-auth: ^4.24.7 => 4.24.7
next-themes: ^0.3.0 => 0.3.0
node-fetch: undefined ()
node-html-parser: undefined ()
ora: undefined ()
os-browserify: undefined ()
p-limit: undefined ()
path-browserify: undefined ()
platform: undefined ()
postcss: ^8 => 8.4.38 (8.4.31)
postcss-flexbugs-fixes: undefined ()
postcss-modules-extract-imports: undefined ()
postcss-modules-local-by-default: undefined ()
postcss-modules-scope: undefined ()
postcss-modules-values: undefined ()
postcss-preset-env: undefined ()
postcss-safe-parser: undefined ()
postcss-scss: undefined ()
postcss-value-parser: undefined ()
prettier: ^3.2.5 => 3.2.5
process: undefined ()
punycode: undefined ()
querystring-es3: undefined ()
raw-body: undefined ()
react: ^18 => 18.2.0
react-builtin: undefined ()
react-dom: ^18 => 18.2.0
react-dom-builtin: undefined ()
react-dom-experimental-builtin: undefined ()
react-experimental-builtin: undefined ()
react-is: 18.2.0
react-refresh: 0.12.0
react-server-dom-turbopack-builtin: undefined ()
react-server-dom-turbopack-experimental-builtin: undefined ()
react-server-dom-webpack-builtin: undefined ()
react-server-dom-webpack-experimental-builtin: undefined ()
regenerator-runtime: 0.13.4
sass-loader: undefined ()
scheduler-builtin: undefined ()
scheduler-experimental-builtin: undefined ()
schema-utils: undefined ()
semver: undefined ()
send: undefined ()
server-only: 0.0.1
setimmediate: undefined ()
sharp: ^0.33.2 => 0.33.2
shell-quote: undefined ()
source-map: undefined ()
stacktrace-parser: undefined ()
stream-browserify: undefined ()
stream-http: undefined ()
string-hash: undefined ()
string_decoder: undefined ()
strip-ansi: undefined ()
superstruct: undefined ()
tailwindcss: ^3.3.0 => 3.4.1
tar: undefined ()
terser: undefined ()
text-table: undefined ()
timers-browserify: undefined ()
ts-node: ^10.9.2 => 10.9.2
tty-browserify: undefined ()
typescript: ^5 => 5.4.3
ua-parser-js: undefined ()
unistore: undefined ()
util: undefined ()
vm-browserify: undefined ()
watchpack: undefined ()
web-vitals: undefined ()
webpack: undefined ()
webpack-sources: undefined ()
ws: undefined ()
zod: undefined ()
npmGlobalPackages:
@aws-amplify/cli: 12.10.1
corepack: 0.22.0
npm: 10.2.3
Describe the bug
I have the following workflow,
- Sign in with custom challenge. The cognito will reply with a magic link.
- Click on the magic link will open up a new tab to send confirmsignin.
That will not work because amplify v6 needs signin and confirmsignin command from 'aws-amplify/auth' to be placed in the same function so that the next step in signin can continue.
However, from "@aws-sdk/client-cognito-identity" package, InitiateAuthCommand and RespondToAuthChallengeCommand can be separated in callbacks by session id.
Expected behavior
Allow signIn and confirmSignIn to be separated.
Reproduction steps
- Install aws-amplify v6
- Create two scripts. One script just to use signIn, another just to use confirmSignIn.
Code Snippet
// Put your code below this line.
async function amplifySignIn(email: string) {
const resp = await login({
username: email,
options: { authFlowType: "CUSTOM_WITHOUT_SRP" },
});
return resp;
}
async function amplifyConfirmSignIn(email: string, code: string) {
const resp = await confirmSignIn({
challengeResponse: code,
});
}
Log output
// Put your logs below this line
confirmSignIn.mjs:58 Uncaught (in promise) SignInException:
An error occurred during the sign in process.
This most likely occurred due to:
1. signIn was not called before confirmSignIn.
2. signIn threw an exception.
3. page was refreshed during the sign in flow.
aws-exports.js
No response
Manual configuration
No response
Additional configuration
No response
Mobile Device
No response
Mobile Operating System
No response
Mobile Browser
No response
Mobile Browser Version
No response
Additional information and screenshots
No response
Hello, @zcemycl and thanks for opening this issue. You are correct that confirmSignIn() currently needs to be called alongside signIn() due to the session information and challengeResponse being required as part of the confirmation flow.
Are you able to provide more context around what the use case is here or why you're needing to call these separately in the authentication flow? Thanks!
@cwomack for example, this one from aws tutorial https://aws.amazon.com/blogs/mobile/implementing-passwordless-email-authentication-with-amazon-cognito/ .
- You login the website by providing email that is in the user pool.
- the custom auth flow allows that user by issuing an auth challenge which is sending the user email a magic link.
- If the user clicks on the magic link, it supposes to send a confirm auth challenge to custom auth flow to verify the user identity.
- BUT since clicking the magic link or copying magic link to the browser will lead refreshing the page, the original signin function is discontinued.
I can replicate that tutorial with "@aws-sdk/client-cognito-identity-provider" but "aws-amplify" is not working.
Related to #10469.
@zcemycl can you review that issue I linked above to see if it would encompass what you're asking for in this issue?
@cwomack I can confirm it is similar, except that issue is from v5 amplify.sendCustomChallengeAnswer . But v5 can integrate nicer with amazon-cognito-identity-js (v2) to solve that issue.
My current issue is based on v6 and i can't see any examples of using amplify v6 and @aws-sdk/client-cognito-identity-provider v3 together.
@zcemycl, thanks for the quick response! I've got this marked as a feature request and will review this internally with the work that is currently underway with the other issue. This may be considered a duplicate if that's the case, but we'll capture the scope (and of course v6 aspect) of what's in this issue if we consider them duplicates.
Following up to say we'll keep both issues open and separate for now, because of the extra context here regarding the new/cross tab functionality described.
We have the exact same use case, where we send a magic link to our users to login without a password. With v5, we're able to serialise the user/session into local storage, and hydrate it once the user clicks on the link in the email, thanks to interop with amazon-cognito-identity-js.
Having this part of amplify auth would be extremely awesome, or else have a way we can implement it on our side.
@zcemycl @mmeylan I have magic link login working in Amplify v6, using the CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE flow and then call confirmSignIn({ challengeResponse: challenge } which will log me in.
For this to work, I have had to setup multiple hooks in Cognito to log you in when you do the custom challenge. Is this what you are looking for?
@mattiLeBlanc Does your implementation work when the magic link is opened in a new tab or after a page reload ? Here's my exact flow:
- User opens sign-in page, enters email (amplify
signIncalled) - Email is sent to user with sign-in challenge in the link
- User clicks on link in email, new page is opened with challenge in the query params (amplify
confirmSignIn({challengeResponse: challenge})called) <-- does not work because session created by 1. does not exist.
As far as I could tell from by tests on v6, the session is stored in memory by amplify, but maybe I am missing something.
@zcemycl @mmeylan I have magic link login working in Amplify v6, using the CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE flow and then call
confirmSignIn({ challengeResponse: challenge }which will log me in.For this to work, I have had to setup multiple hooks in Cognito to log you in when you do the custom challenge. Is this what you are looking for?
@mmeylan Can you please let us know what changes have you made to work it. like you implemented hooks.
@mattiLeBlanc @mmeylan Any update on your solution? We have a very similar issue.
@mmeylan It can work on both, but if you open in the same tab or window (with localstorage), you have to programmatically logout before processing the hook, at least that is what I do.
So what I do:
- I create a new cognito user, create a token, put that token as a custom:authChallenge attr in the cognito user
- I construct the link with a websafe version of the token
- user opens link, goes to website, token gets validated in backend and decoded and login:
....
return this.programmaticLogout({ clearState: true }).pipe(
switchMap(() => this.signIn({ username })
.pipe(
switchMap(res => {
if (res === 'CONFIRM_SIGN_IN_WITH_CUSTOM_CHALLENGE') {
return from(confirmSignIn({ challengeResponse: challenge }))
.pipe(
map(res => res.nextStep.signInStep)
);
} else {
return of(res);
}
}),
switchMap(status => {
if (status === 'DONE') {
return this.getAuthSession()
}
return undefined;
}),
....
I had to setup plenty of hooks in the Auth stack based on info from : -https://theburningmonk.com/2023/03/implementing-magic-links-with-amazon-cognito-a-step-by-step-guide/ -https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-define-auth-challenge.html#aws-lambda-triggers-define-auth-challenge-example
I am a bit busy but if you are still having issues, I got try setting up a test stack in gtihub that works, you will have to deploy it your self of course, but you could test it.
We have the same issue with Cognito's new passwordless feature. We want to send an email with a magic link (we use the CustomMessage Lambda function to compose and send it - including the code itself). The user can click the link in the email. Hence, we can't call signIn again as it would sent another magic link.
Hey @ronnyroeller, thanks for chiming in and letting us know you're also experiencing friction here. We've got this marked as a feature request and are reviewing internally to come up with a solution.
We are experiencing the same issue, and according to the Passwordless sign-in with one-time passwords documentation, we have encountered the following problems:
Issues
-
Missing
SessioninAuth.signInResponse:- The
Sessionattribute is not included in the response ofAuth.signIn. However, theSessionis required to complete the authentication process usingAuth.confirmSignIn.
- The
-
SessionNeeded in the Email Template:- Since
Sessionis necessary forAuth.confirmSignIn, it is also required in the email template to include it in the query string of the magic link (e.g., https://login.example.com/signin?code=12345678&session=<Session>).
- Since
-
Set
SessionTimeout:- The
Sessiontimeout is currently less than 5 minutes, which is not suitable in some cases. If we call theAuth.confirmSignInrequest more than 5 minutes after theAuth.signInrequest, it throws the error:Invalid session for the user, session is expired. - There should be an option to configure the
Sessiontimeout to suit different use cases.
- The
Hey @eacet, thanks for adding additional momentum here. We are currently working towards implementing some changes that should make the flow you are describing possible. We'll follow up here when we have more information to share.
In the meantime, feel free to checkout some of the other passwordless options to see if any fit your use case.
We're dealing with pretty similar issue with Amplify v6 too. Looking forward to the solution to this
Does the Amplify team have a status update on supporting this flow?
Hi @brandonhall ,
We are still evaluating the security implication of this feature, thank you for your patience.
My business owners think I'm junk because I can't implement a "simple" magic link with Cognito that every other company can.
If I call fetchAuthSession() and store the sessionToken to retrieve it for use in confirmSingIn(), will that work? @eacet , I tried including it as a URL query parameter manually when calling the page that does confirmSignIn(), but this did not yield any results. Perhaps I should encodeUrlComponent(sessionToken)? Did you find any other methods to circumvent this limitation?
It looks like the fact that session information doesn't transfer from one tab to another is what ruins the flow.
Hi @malikalimoekhamedov @zcemycl
You may find the sample app for passwordless sign-in helpful implementing a magic link flow.
Regarding the question,
If I call fetchAuthSession() and store the sessionToken to retrieve it for use in confirmSingIn(), will that work?
This will not work unfortunately. The session token used by confirmSignIn() / respondToAuthChallenge can not be set from external.