-
Notifications
You must be signed in to change notification settings - Fork 197
DO NOT MERGE: new auth method #1483
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
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! Left some nitpicky comments.
params.redirectParams | ||
); | ||
|
||
const isMfaRequired = multiFactors ? multiFactors?.length > 0 : false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Very nit) No need for the ?.
, we know multiFactors
is present in that branch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah good catch
account-kit/signer/src/base.ts
Outdated
case "otp": | ||
return this.authenticateWithOtpNew(params); | ||
default: | ||
throw new Error("type not implemented"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Minor) I'd recommend using assertNever
to check that all types are handled, which also means explicitly writing out the other cases. That way, if we add a new type of auth step the type system will make us explicitly acknowledge it here. I'm thinking something like:
switch (type) {
case "email":
return this.authenticateWithEmailNew(params);
case "otp":
return this.authenticateWithOtpNew(params);
case "passkey":
case "oauth":
case "oauthReturn":
throw new Error(`Unsupported auth step type: ${type}`);
default:
assertNever(type, `Unknown auth step type: ${type}`);
}
Over time we've had a number of issues in the sdk where we added a new union arm and forgot to add handling for it somewhere, so IMO it's worth the extra hassle.
(I also suggest including the type in the error message to make debugging easier if this happens.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah good call, will updated 👍
account-kit/signer/src/base.ts
Outdated
}; | ||
} | ||
|
||
if (!("email" in params)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check isn't strictly necessary because the type system should supposedly enforce that email
is present in this branch, but doesn't hurt I suppose.
} | ||
); | ||
|
||
authenticateStep: (params: AuthParams) => Promise<AuthStepResult> = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit because this also starts and progresses the flow should the name be handleAuth
, authenticateOrAdvance
, or progressAuth
?
Should we break up starting and progressing authentication into two calls? Such as login
and verify
?
Closing as I plan to further investigate the different approaches here |
Pull Request Checklist
yarn test
)site
folder, and guidelines for updating/adding docs can be found in the contribution guide)feat!: breaking change
)yarn lint:check
) and fix any issues? (yarn lint:write
)PR-Codex overview
This PR focuses on enhancing the authentication flow by introducing support for multi-factor authentication (MFA) and refining the handling of different authentication steps in the
BaseAlchemySigner
class.Detailed summary
AuthStepResult
type to represent various authentication states.AuthParams
type to include MFA parameters.authenticateStep
method to handle different auth types, including MFA.authenticateWithOtpNew
andauthenticateWithEmailNew
methods for improved OTP and email handling.validateMultiFactors
to returnAuthStepResult
instead ofUser
.Goal:
We’ve updated our API to improve multi-factor authentication (MFA) flows by adding a new validate-mfa endpoint. Previously, you had to submit all MFA credentials (e.g., TOTP) with your primary credentials (like email + otp) in a single call, which meant you couldn’t provide incremental feedback to the user if one step failed.
Now that we have a new endpoint for MFA, it makes sense to refine the SDK’s authentication flow by introducing a authenticateStep method that returns a status after each step—rather than always returning a final User or throwing an error. This is especially important for multi-step flows like email + otp + totp.
Currently, the existing authenticate method returns a User or throws an error. This approach can lead to unresolved Promises across multiple steps in an MFA flow, forcing developers to rely on events to figure out which step the user is on.
Possible MFA flow with the current
authenticate
methodThis sequence can be confusing because each call to authenticate returns a promise that waits for future steps, rather than returning partial information at each step.
Proposed Flow with
authenticateStep
Each call returns immediate feedback about the current status (AWAITING_EMAIL_AUTH, AWAITING_MFA_AUTH, etc.) rather than suspending the promise until all steps are complete. This means you can handle errors or partial progress more cleanly.
Note: We won’t break backward compatibility. The existing authenticate method continues to work as before, but we recommend switching to authenticateStep for multi-step flows.