Is it possible to implement SSO with SAML using React and .NET 7/.NET Core?

I am trying to implement SSO with SAML 2.0 in a React application with .NET 7 as the back end. With this documentation from Okta I was able to create a SAML authentication in .NET 7 and it works fine with Razor pages. But I am not able to figure out how to add React into this. When I try to redirect from front-end to back-end, it enters an infinite loop. Here’s a snippet from my React code:

const App: React.FunctionComponent<IApplicationProps> = props => {
    const [loading, setLoading] = useState<boolean>(true);
    const [email, setEmail] = useState<string>('');
    useEffect(() => {
    const urlParams = new URLSearchParams(window.location.search);
        const jwtToken = urlParams.get('jwt');
        debugger;

        if (jwtToken) {
            // Store the JWT token in local storage or a secure client-side storage
            // for further use in API calls or authentication checks
            localStorage.setItem('token', jwtToken);
            debugger;
            // Make API calls or perform authentication checks using the JWT token
            axios({
                method: 'GET',
                url: 'https://localhost:44379/auth/check',
                withCredentials: true,
                headers: {
                    Authorization: `Bearer ${jwtToken}`,
                },
            }).then((response) => {
                  debugger;
                    console.log("aa",response);

                    if (response.data !== "") {
                        const { user } = response.data;
                        setEmail(user);
                        setLoading(false);
                    } else {
                        RedirectToLogin();
                    }
                })
                .catch((error) => {
                    console.error(error, 'SAML');
                    RedirectToLogin();
                });
        } else {
            RedirectToLogin();
        }
    }, []);

    const RedirectToLogin = () => {
        window.location.replace('https://localhost:44379/auth/login');
    }

    if (loading)
        return <p>loading ...</p>

    return (
        <p>Hello {email}!</p>
    );
}

export default App;

Any help would be really appreciated.

Hello,

The blog post demonstrates a Web SAML Application which uses Razor to render dynamic content, but still server side rendering.

With a Single Page Application such as React typically it would handle it’s own login using a custom solution or OAuth2/OIDC flow and then store tokens locally.

Can you explain a bit more what you are are trying to setup. I see a reference to JWT and local storage, but that would indicate that your React App is doing some sort of OAuth flow?

Not sure why you would need a SAML login, but then protect server side routes with requiring a bearer token. Why not remove the SAML piece and have the React App do an authorization code flow and use the returned access_token to make calls to protected routes in the .NET app?

2 Likes

Hi @Erik,

First of all, thank you for your answer.

Sorry for the misunderstanding, I am not using OAuth in my React app. What I want to do is simply use SAML for authentication. I used JWT just to attempt to notify the React app about authentication, but it didn’t work, of course. Essentially, I want to authenticate users using SAML on the backend and then notify the frontend by returning the authenticated user. I don’t know whether doing this authentication with .NET side and return the authenticated user to React side is possible or not.

If I need to provide a more detailed explanation, in the current state of the project, I am starting the project from the React project (http://localhost:3000). Then, I redirect to the .NET project (https://localhost:5001) for the login process. After successfully authenticating on the Okta page, I redirect back to localhost:3000. I can see the claims on the localhost:5001 page and I am authenticated there, but I cannot authenticate on localhost:3000. I am aware that I am following the wrong method, but I cannot find another solution and I am stuck. Instead of redirecting to localhost:5001, I tried using the .NET project as an API for the React project, but I got the same result again.