Skip to content

Commit

Permalink
Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
shenj committed Nov 22, 2024
1 parent b228f19 commit 74b4431
Show file tree
Hide file tree
Showing 17 changed files with 510 additions and 325 deletions.
46 changes: 32 additions & 14 deletions lib/msal-native-auth/doc/tech-design/Tech Design.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,27 @@ async function handleSignIn(event) {

switch (result.state) {

This comment has been minimized.

Copy link
@axhaferllari

axhaferllari Nov 22, 2024

This solution is not ideal in a real work front end app because there might be different scenarios:

  • Example Login Screen is not connected to Enter Code Screen, might be 2 different routes
  • navigateToCodeEntryView implementation in real app can be totally route based, loosing the state between components
  • A singleton approach might be more beneficial (ex same as MSAL instance variable`)
case SignInState.Completed:
// read the account info from result by result.data and use it to get account data, tokens, and sign out.
accountInfo = result.data;
const accessToken = await accountInfo.getAccessToken();
fetchProfile(accessToken);
break;
case SignInState.CodeRequired:
navigateToCodeEntryView(result.stateHandler);
break;
case SignInState.PasswordRequired:
navigateToPasswordEntryView(result.stateHandler);
break;
case SignInState.Failed:
// check the error type by calling result.error and handle error
if (result.error instanceof UserNotFoundError) {
// Handle user not found error
} else {
// Handle unexpected error
}
break;
default:
throw new Error("Invalid sign in state");
}
}

Expand All @@ -73,14 +87,16 @@ async function submitCode(handler: SignInCodeRequiredStateHandler) {

const result = handler.submitCode(code);

// Handling the error if the action is failed
if (!result.isSuccess) {
return;
switch (result.state) {
case SignInState.Completed:
// read the account info from result by result.data and use it to get account data, tokens, and sign out.
break;
case SignInState.Failed:
// check the error type by calling result.error and handle error
break;
default:
throw new Error("Invalid sign in state");
}

accountInfo = result.data;
const accessToken = await accountInfo.getAccessToken();
fetchProfile(accessToken);
}

// In the Password Entry UI
Expand All @@ -89,14 +105,16 @@ async function submitPassword(handler: SignInPasswordRequiredStateHandler) {

const result = handler.submitPassword(password);

// Handling the error if the action is failed
if (!result.isSuccess) {
return;
switch (result.state) {
case SignInState.Completed:
// read the account info from result by result.data and use it to get account data, tokens, and sign out.
break;
case SignInState.Failed:
// check the error type by calling result.error and handle error
break;
default:
throw new Error("Invalid sign in state");
}

accountInfo = result.data;
const accessToken = await accountInfo.getAccessToken();
fetchProfile(accessToken);
}
```

Expand Down
161 changes: 47 additions & 114 deletions lib/msal-native-auth/samples/SignInSample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@
*/

import {
SignInCodeRequiredState,
SignInPasswordRequiredState,
UserNotFoundError,
SignInCodeRequiredStateHandler,
SignInPasswordRequiredStateHandler,
SignInState,
} from "@azure/msal-native-auth";
import { AccountInfo } from "@azure/msal-native-auth";
import { SignInInputs } from "@azure/msal-native-auth";
import { NativeAuthConfiguration } from "@azure/msal-native-auth";
import { NativeAuthPublicClientApplication } from "@azure/msal-native-auth";

// This sample demonstrates how to sign in a user using the MSAL Native Auth library.
// Currently, this sample doesn't work and only is used to demonstrate the usage of the library.
// Currently, this sample doesn't work and is only used to demonstrate the usage of the library.
export async function signin(
username: string,
password?: string
Expand All @@ -28,120 +27,54 @@ export async function signin(

const signInOptions: SignInInputs = {
username: username,
password: password,
};

const result = await app.signIn(signInOptions);

if (!result.isSuccess) {
// check the errr type and handle error

if (result.error instanceof UserNotFoundError) {
// handle user not found error
} else {
// handle unexpected error
}

return;
}

// Check if the flow is completed
if (result.isFlowCompleted()) {
// Get the account info which can be used to get account data, tokens, and sign out.
const accountManager: AccountInfo = result.data as AccountInfo;

accountManager.getAccount();
accountManager.getIdToken();
await accountManager.getAccessToken();
await accountManager.signOut();

return;
}

// code required
if (result.state instanceof SignInCodeRequiredState) {
// collect code from customer.
const code = "test-code";

const submitCodeResult = await result.state.submitCode(code);

if (!submitCodeResult.isSuccess) {
// handle error

switch (result.state) {
case SignInState.Completed:
// read the account info from result by result.data and use it to get account data, tokens, and sign out.
return;
}

// Get the account manager which can be used to get account information, tokens, and sign out.
const accountManager: AccountInfo =
submitCodeResult.data as AccountInfo;

accountManager.getAccount();
accountManager.getIdToken();
await accountManager.getAccessToken();
await accountManager.signOut();

return;
}

// resend code and submit code
if (result.state instanceof SignInCodeRequiredState) {
// resend code
const resendCodeResult = await result.state.resendCode();

if (!resendCodeResult.isSuccess) {
// handle error

case SignInState.CodeRequired:
// collect code from customer.
const code = "test-code";

const submitCodeResult = await (
result.stateHandler as SignInCodeRequiredStateHandler
).submitCode(code);

switch (submitCodeResult.state) {
case SignInState.Completed:
// read the account info from result by submitCodeResult.data and use it to get account data, tokens, and sign out.
return;
case SignInState.Failed:
// check the error type by calling result.error and handle error

This comment has been minimized.

Copy link
@axhaferllari

axhaferllari Nov 22, 2024

In case of failure the function should throw an exception with the error details, ex:

try {
const submitCodeResult = await (
                result.stateHandler as SignInCodeRequiredStateHandler
            ).submitCode(code);
} catch(error) {
   alert(error);//
}
break;
default:
throw new Error("Invalid sign in state");
}
case SignInState.PasswordRequired:
// collect password from customer.
const password = "test-pwd";

const submitPasswordResult = await (
result.stateHandler as SignInPasswordRequiredStateHandler
).sumbmitPassword(password);

switch (submitPasswordResult.state) {
case SignInState.Completed:
// read the account info from result by submitPasswordResult.data and use it to get account data, tokens, and sign out.
return;
case SignInState.Failed:
// check the error type by calling result.error and handle error
break;
default:
throw new Error("Invalid sign in state");
}
case SignInState.Failed:
// check the error type by calling result.error and handle error
return;
}

// collect code from customer.
const code = "test-code";

const submitCodeResult = await (
resendCodeResult.state as SignInCodeRequiredState
).submitCode(code);

if (!submitCodeResult.isSuccess) {
// handle error

return;
}

// Get the account manager which can be used to get account information, tokens, and sign out.
const accountManager: AccountInfo =
submitCodeResult.data as AccountInfo;

accountManager.getAccount();
accountManager.getIdToken();
await accountManager.getAccessToken();
await accountManager.signOut();

return;
}

// password required
if (result.state instanceof SignInPasswordRequiredState) {
// collect password from customer.
const pwd = "test-password";
const submitPasswordResult = await result.state.sumbmitPassword(pwd);

if (!submitPasswordResult.isSuccess) {
// handle error

return;
}

// Get the account manager which can be used to get account information, tokens, and sign out.
const accountManager: AccountInfo =
submitPasswordResult.data as AccountInfo;

accountManager.getAccount();
accountManager.getIdToken();
await accountManager.getAccessToken();
await accountManager.signOut();

return;
default:
throw new Error("Invalid sign in state");
}
}

console.log("Starting sign in sample...");
110 changes: 37 additions & 73 deletions lib/msal-native-auth/samples/lib/msal-native-auth.samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* Licensed under the MIT License.
*/
// This sample demonstrates how to sign in a user using the MSAL Native Auth library.
// Currently, this sample doesn't work and only is used to demonstrate the usage of the library.
// Currently, this sample doesn't work and is only used to demonstrate the usage of the library.
async function signin(username, password) {
const config = {
auth: { clientId: "test-client-id" },
Expand All @@ -19,86 +19,50 @@
const app = msalNativeAuth.NativeAuthPublicClientApplication.create(config);
const signInOptions = {
username: username,
password: password,
};
const result = await app.signIn(signInOptions);
if (!result.isSuccess) {
// check the errr type and handle error
if (result.error instanceof msalNativeAuth.UserNotFoundError) ;
return;
}
// Check if the flow is completed
if (result.isFlowCompleted()) {
// Get the account info which can be used to get account data, tokens, and sign out.
const accountManager = result.resultData;
accountManager.getAccount();
accountManager.getIdToken();
await accountManager.getAccessToken();
await accountManager.signOut();
return;
}
// code required
if (result.nextStateHandler instanceof msalNativeAuth.SignInCodeRequiredState) {
// collect code from customer.
const code = "test-code";
const submitCodeResult = await result.nextStateHandler.submitCode(code);
if (!submitCodeResult.isSuccess) {
// handle error
return;
}
// Get the account manager which can be used to get account information, tokens, and sign out.
const accountManager = submitCodeResult.resultData;
accountManager.getAccount();
accountManager.getIdToken();
await accountManager.getAccessToken();
await accountManager.signOut();
return;
}
// resend code and submit code
if (result.nextStateHandler instanceof msalNativeAuth.SignInCodeRequiredState) {
// resend code
const resendCodeResult = await result.nextStateHandler.resendCode();
if (!resendCodeResult.isSuccess) {
// handle error
return;
}
// collect code from customer.
const code = "test-code";
const submitCodeResult = await resendCodeResult.nextStateHandler.submitCode(code);
if (!submitCodeResult.isSuccess) {
// handle error
switch (result.state) {
case msalNativeAuth.SignInState.Completed:
// read the account info from result by result.data and use it to get account data, tokens, and sign out.
return;
}
// Get the account manager which can be used to get account information, tokens, and sign out.
const accountManager = submitCodeResult.resultData;
accountManager.getAccount();
accountManager.getIdToken();
await accountManager.getAccessToken();
await accountManager.signOut();
return;
}
// password required
if (result.nextStateHandler instanceof msalNativeAuth.SignInPasswordRequiredState) {
// collect password from customer.
const pwd = "test-password";
const submitPasswordResult = await result.nextStateHandler.sumbmitPassword(pwd);
if (!submitPasswordResult.isSuccess) {
// handle error
case msalNativeAuth.SignInState.CodeRequired:
// collect code from customer.
const code = "test-code";
const submitCodeResult = await result.stateHandler.submitCode(code);
switch (submitCodeResult.state) {
case msalNativeAuth.SignInState.Completed:
// read the account info from result by submitCodeResult.data and use it to get account data, tokens, and sign out.
return;
case msalNativeAuth.SignInState.Failed:
// check the error type by calling result.error and handle error
break;
default:
throw new Error("Invalid sign in state");
}
case msalNativeAuth.SignInState.PasswordRequired:
// collect password from customer.
const password = "test-pwd";
const submitPasswordResult = await result.stateHandler.sumbmitPassword(password);
switch (submitPasswordResult.state) {
case msalNativeAuth.SignInState.Completed:
// read the account info from result by submitPasswordResult.data and use it to get account data, tokens, and sign out.
return;
case msalNativeAuth.SignInState.Failed:
// check the error type by calling result.error and handle error
break;
default:
throw new Error("Invalid sign in state");
}
case msalNativeAuth.SignInState.Failed:
// check the error type by calling result.error and handle error
return;
}
// Get the account manager which can be used to get account information, tokens, and sign out.
const accountManager = submitPasswordResult.resultData;
accountManager.getAccount();
accountManager.getIdToken();
await accountManager.getAccessToken();
await accountManager.signOut();
return;
default:
throw new Error("Invalid sign in state");
}
}
console.log("Starting sign in sample...");

async function test_signin() {
signin("test-username", "test-password");
signin("test-username");
}
test_signin();

Expand Down
Loading

0 comments on commit 74b4431

Please sign in to comment.