Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to register user if not already registered #131

Open
brno32 opened this issue Jan 2, 2024 · 7 comments
Open

Add option to register user if not already registered #131

brno32 opened this issue Jan 2, 2024 · 7 comments

Comments

@brno32
Copy link
Contributor

brno32 commented Jan 2, 2024

The following code silently exits if the user does not exist in the user pool

This is good default behavior, as it prevents user enumeration.

However, it would be nice if there was an option to automatically register a user instead of silently erroring.

An option taken from the Passwordless cdk construct could be added here

if (event.request.userNotFound) {

What I would like to do is register a user and have their first magic link email also verify their email when they sign in for the first time. I do not want a separate register page.

@ottokruse
Copy link
Contributor

ottokruse commented Jan 3, 2024

Thanks for the suggestion.

Had a similar discussion in #92 and #96

A problem for backend solutions as you suggest, is that in case the user does not exist and a "dummy" auth flow is started to prevent user enumeration, that the Cognito trigger payload does not show the alias the user used to sign in with, so you don't know their email address.

I'm not aware of any way around this currently.

Only option is to orchestrate this from the frontend as suggested in the discussion in #92, or build a custom API in front of Cognito.

Open to any other suggestions though!

@brno32
Copy link
Contributor Author

brno32 commented Jan 3, 2024

What if this feature required the email to also be part of the payload, or it could only be enabled if the app stores the email as the username? (this is what I'm doing for my app)

@ottokruse
Copy link
Contributor

Yeah we could add the email address in the payload, good idea. Can add it in the client metadata of the respondToAuth challenge call. Then it's visible in the createAuthChallenge trigger.

Yeah, think I like that! Many users want this, as evidenced by the other issues logged for this.

@brno32
Copy link
Contributor Author

brno32 commented Jan 7, 2024

would this be possible to do from within requestSignInLink? I see it's already an authParameter, but these attributes don't seem to make their way into the event payload server-side

@ottokruse
Copy link
Contributor

It is a known "issue" that the clientMetadata that you send in initiateAuth is not visible in the Lambda triggers (such as the CreateAuthChallenge trigger). However, the clientMetadata that you send in responseToAuthChallenge is visible in the Lambda triggers, so therein lies the solution.

For magic link, we always send a "PROVIDE_AUTH_PARAMETERS" challenge first, and the the client must respond with the auth parameters using responseToAuthChallenge, so there we could then plug the logic in to register the new user.

What's your idea about the automatic account creation. Should we do that, or ask the user for consent first, e.g. the e-mail could say something like "you requested a sign-in link but you don't have an account with us yet, click [here] to proceed and create an account with us". I think that may be nicer, but then we need more plumbing to handle that click, and only then create the account.

@brno32
Copy link
Contributor Author

brno32 commented Jan 8, 2024

What's your idea about the automatic account creation. Should we do that, or ask the user for consent first, e.g. the e-mail could say something like "you requested a sign-in link but you don't have an account with us yet, click [here] to proceed and create an account with us". I think that may be nicer, but then we need more plumbing to handle that click, and only then create the account.

I'd say supporting both would be worth it. Personally, we would like to automatically just register the user and send the magic link, but I think it would be good to also support a flow that requires user consent.

For magic link, we always send a "PROVIDE_AUTH_PARAMETERS" challenge first, and the the client must respond with the auth parameters using responseToAuthChallenge, so there we could then plug the logic in to register the new user.

Is the code that runs after respondToAuthChallenge where this could go here? https://github.com/aws-samples/amazon-cognito-passwordless-auth/blob/main/cdk/custom-auth/verify-auth-challenge-response.ts

@ottokruse
Copy link
Contributor

Is the code that runs after respondToAuthChallenge where this could go here? https://github.com/aws-samples/amazon-cognito-passwordless-auth/blob/main/cdk/custom-auth/verify-auth-challenge-response.ts

Yes but Define Auth Challenge and Create Auth Challenge will also run again, in fact a whole chain runs after respondToAuthChallenge.

It works like this. Each custom auth flow triggers a chain of Define Auth Challenge, Create Auth Challenge and Verify Auth Challenge calls. This chain stops when you, in Define Auth Challenge return issueTokens: true or failAuthentication: true. But it goes on for as long as you don't return that, so that you can create multiple challenges, one after the other (e.g. first password, and then SMS OTP).

In our magic link implementation the chain looks like this:

graph TD;
    IA(client:InitiateAuth)-->DA(cognito:DefineAuthChallenge - CUSTOM_CHALLENGE);
    DA-->CA(cognito:CreateAuthChallenge- Provide auth parameters);
    CA-->RAC(client:RespondToAuthChallenge - I want a magic link);
    RAC-->VA(cognito:VerifyAuthChallengeResponse - dummy);
    VA-->DA2(cognito:DefineAuthChallenge  - CUSTOM_CHALLENGE);
    DA2-->CA2(cognito:CreateAuthChallenge - send magic link);
    CA2-->RAC2(client:RespondToAuthChallenge - provide magic link hash);
    RAC2-->VA2(cognito:VerifyAuthChallengeResponse - verify magic link hash);
    VA2-->DA3(cognito:DefineAuthChallenge - issueTokens true);
    DA3-->DONE(Done, JWTs issued to client);
Loading

(Refer to the Sequence diagrams for more detail)

We could make user consent another challenge, but for now since you don't need it we can skip it also.

Have to pick the best spot to do user auto registration in, might be best in the 2nd CreateAuthChallenge step above.

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

No branches or pull requests

2 participants