Skip to content

Commit

Permalink
Mfa required function/state
Browse files Browse the repository at this point in the history
  • Loading branch information
danielholmes committed Feb 1, 2024
1 parent 25d2bf3 commit a3a88d7
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@dhau/react-aws-cognito",
"version": "0.0.13",
"version": "0.0.14",
"type": "module",
"sideEffects": false,
"description": "Context and hooks to manage an AWS Cognito authenticated user in React.",
Expand Down
9 changes: 8 additions & 1 deletion src/model/internal-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,18 @@ type NewPasswordInternalAuthState = {
readonly user: CognitoUser;
};

type MfaRequiredInternalAuthState = {
readonly type: "mfaRequired";
readonly user: CognitoUser;
};

type InternalAuthState<TUser> =
| LoadingInternalAuthState
| ErrorInternalAuthState
| SignedInInternalAuthState<TUser>
| SignedOutInternalAuthState
| NewPasswordInternalAuthState;
| NewPasswordInternalAuthState
| MfaRequiredInternalAuthState;

type InternalAuthStateSetter<TUser> = (
state: InternalAuthState<TUser & AuthAccess>,
Expand All @@ -40,6 +46,7 @@ export type {
InternalAuthState,
NewPasswordInternalAuthState,
SignedOutInternalAuthState,
MfaRequiredInternalAuthState,
SignedInInternalAuthState,
InternalAuthStateSetter,
};
36 changes: 36 additions & 0 deletions src/model/require-mfa-complete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { CognitoUser } from "amazon-cognito-identity-js";
import { InternalAuthStateSetter } from "./internal-state";
import { UserParser, getUserData } from "./get-current-user";

async function requireMfaComplete<TUser>(
setInternalAuthState: InternalAuthStateSetter<TUser>,
parseUser: UserParser<TUser>,
user: CognitoUser,
code: string,
) {
// TODO: Look at source - use UserPool instead
// https://github.com/aws-amplify/amplify-js/blob/master/packages/
// amazon-cognito-identity-js/src/CognitoUser.js
// This one is a bit more involved
await new Promise<void>((resolve, reject) => {
user.sendMFACode(
code,
{
onSuccess() {
resolve();
},
onFailure: reject,
},
"SOFTWARE_TOKEN_MFA",
);
});

const authUser = await getUserData(user, parseUser);
setInternalAuthState({
type: "signedIn",
user,
authUser,
});
}

export default requireMfaComplete;
9 changes: 6 additions & 3 deletions src/model/sign-in.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ type SignInResult =
}
| {
readonly type: "mfa";
readonly user: CognitoUser;
};

async function signIn<TUser>(
Expand All @@ -30,7 +29,7 @@ async function signIn<TUser>(
parseUser: UserParser<TUser>,
email: string,
password: string,
): Promise<SignInResult> {
) {
const authDetails = new AuthenticationDetails({
Username: email,
Password: password,
Expand All @@ -57,7 +56,11 @@ async function signIn<TUser>(
resolve({ type: "newPassword" });
},
totpRequired() {
resolve({ type: "mfa", user });
setInternalAuthState({
type: "mfaRequired",
user,
});
resolve({ type: "mfa" });
},
});
});
Expand Down
12 changes: 12 additions & 0 deletions src/signed-out-auth-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ import {
SignedOutInternalAuthState,
NewPasswordInternalAuthState,
InternalAuthStateSetter,
MfaRequiredInternalAuthState,
} from "./model/internal-state";
import { UserParser } from "./model/get-current-user";
import signIn from "./model/sign-in";
import requireMfaComplete from "./model/require-mfa-complete";

type Options<TUser> = {
readonly userPool: CognitoUserPool;
readonly storage: Storage;
readonly internalAuthState:
| SignedOutInternalAuthState
| MfaRequiredInternalAuthState
| NewPasswordInternalAuthState;
readonly setInternalAuthState: InternalAuthStateSetter<TUser>;
readonly parseUser: UserParser<TUser>;
Expand Down Expand Up @@ -47,6 +50,15 @@ function createSignedOutAuthState<TUser>({
userPool,
storage,
}),
requireMfaComplete:
internalAuthState.type === "mfaRequired"
? partial(
requireMfaComplete,
setInternalAuthState,
parseUser,
internalAuthState.user,
)
: undefined,
requireNewPasswordComplete:
internalAuthState.type === "newPassword"
? partial(
Expand Down

0 comments on commit a3a88d7

Please sign in to comment.