Microsoft Entra ID
Authentication

Tutorial Native Authentication Single Page App React Sdk Sign In

In brief

The tutorial’s code comment was corrected from “Thge” to “The” and from “rquired” to “required.”

What Entra admins need to know

Administrators and developers can follow clearer tutorial guidance; no action is required.

This editorial summary was generated by AI from the documentation changes. Verify important details in the full Microsoft Learn article.

Documentation change

The comparison below shows only the changed extract. Use the full-page view for complete context.

[!INCLUDE applies-to-external-only]

In this tutorial, you learn how to sign in users into a React single-page app (SPA) by using native authentication JavaScript SDK.

In this tutorial, you:

  1. Create a folder called src/app/sign-in.

  2. Create sign-in/components/InitialForm.tsx file, then paste the code from sign-in/components/InitialForm.tsx. This component displays a form that collects a user's username (email).

  3. If your choice of authentication method is email and one-time passcode, create a sign-in/components/CodeForm.tsx file, then paste the code from sign-in/components/CodeForm.tsx. If the administrator sets email one-time passcode as the sign-in flow in the Microsoft Entra admin center, this component displays a form to collect the one-time passcode from the user.

  4. If your choice of authentication method is email and password, create a sign-in/components/PasswordForm.tsx file, then paste the code from sign-in/components/PasswordForm.tsx. This component displays a form that collects a user's password.

  5. Create a sign-in/components/UserInfo.tsx file, then paste the code from sign-in/components/UserInfo.tsx. This component displays a signed-in user's username and sign-in status.

Handle form interactions

  SignInCompletedState,
  AuthFlowStateBase,
} from "@azure/msal-browser/custom-auth";

export default function SignIn() {
    const [authClient, setAuthClient] = useState<ICustomAuthPublicClientApplication | null>(null);
    const [username, setUsername] = useState("");
    const [data, setData] = useState<CustomAuthAccountData | undefined>(undefined);
    const [loadingAccountStatus, setLoadingAccountStatus] = useState(true);
    const [isSignedIn, setCurrentSignInStatus] = useState(false);

    useEffect(() => {
        const initializeApp = async () => {
            const appInstance = await CustomAuthPublicClientApplication.create(customAuthConfig);
            setAuthClient(appInstance);
        };

        initializeApp();
    }, []);

    useEffect(() => {
        const checkAccount = async () => {
            if (!authClient) return;

            const accountResult = authClient.getCurrentAccount();

            if (accountResult.isCompleted()) {
                setCurrentSignInStatus(true);
            }

            setData(accountResult.data);

            setLoadingAccountStatus(false);
        };

        checkAccount();
    }, [authClient]);

    const renderForm = () => {
        if (loadingAccountStatus) {
            return;
        }

        if (isSignedIn || signInState instanceof SignInCompletedState) {
            return <UserInfo userData={data} />;
        }
        if (signInState instanceof SignInCodeRequiredState) {
            return <CodeForm onSubmit={handleCodeSubmit} code={code} setCode={setCode} loading={loading} />;
        }

        return <InitialForm onSubmit={startSignIn} username={username} setUsername={setUsername} loading={loading} />;
    };

    return (
        <div style={styles.container}>
            <h2 style={styles.h2}>Sign In</h2>
    e.preventDefault();
    setError("");
    setLoading(true);

    if (!authClient) return;

    // Start the sign-in flow
    const result = await authClient.signIn({
        username,
    });

    // ThgeThe result may have the different states,
    // such as Password required state, OTP code rquiredrequired state, Failed state and Completed state.

    if (result.isFailed()) {
        if (result.error?.isUserNotFound()) {
            setError("User not found");
            setError("Username is invalid");
        } else if (result.error?.isPasswordIncorrect()) {
            setError("Password is invalid");

        } else {
            setError(`An error occurred: ${result.error?.errorData?.errorDescription}`);
        }
    }

    if (result.isCompleted()) {
        setData(result.data);
    }

    setSignInState(result.state);

    setLoading(false);
};
```
  • If your choice of authentication flow is email and one-time passcode, submit the one-time passcode by using the following code snippet. See a full example at sign-in/page.tsx to learn where to place the code snippet:

        e.preventDefault();
        setError("");
        setLoading(true);
    
        if (signInState instanceof SignInCodeRequiredState) {
            const result = await signInState.submitCode(code);
    
            // the result object may have the different states, such as Failed state and Completed state.
    
            if (result.isFailed()) {
                if (result.error?.isInvalidCode()) {
                    setError("Invalid code");
                    setError(result.error?.errorData?.errorDescription || "An error occurred while verifying the code");
                }
            }
    
            if (result.isCompleted()) {
                setData(result.data);
                setSignInState(result.state);
            }
        }
    
        setLoading(false);
    };
    

    Sign in state's submitCode() submits the one-time passcode.

  • If your choice of authentication flow is email and password, submit the user's password by using the following code snippet. See a full example at sign-in/page.tsx to learn where to place the code snippet:

    const handlePasswordSubmit = async (e: React.FormEvent) => {
        e.preventDefault();
        setError("");
        setLoading(true);
    
        if (signInState instanceof SignInPasswordRequiredState) {
            const result = await signInState.submitPassword(password);
    
            if (result.isFailed()) {
                if (result.error?.isInvalidPassword()) {
                    setError("Incorrect password");
                    );
                }
            }
    
            if (result.isCompleted()) {
                setData(result.data);
    
                setSignInState(result.state);
            }
        }
    
        setLoading(false);
    };
    

Run and test your app

Use the steps in Run and test your app to run your app, then test sign-in flow.

Related content

Daily Entra.News

Get daily email updates

Get a concise summary of the latest Microsoft Entra updates delivered straight to your inbox.

Loading the secure signup form…