In your scenario, you are making a GET request from a ReactJS application to a backend server (b.com), which then redirects you to an SSO server (sso.example.com). However, you encounter a CORS error because the SSO server does not include the necessary CORS headers in its response.
The easiest solution is to implement a workaround on your backend server (b.com). Instead of directly redirecting to the SSO server, you can set up a proxy endpoint on b.com that handles the redirection. When a request to /users lacks proper authorization, the backend should redirect to the proxy endpoint instead of directly to the SSO server. The proxy endpoint can then perform an internal server-side redirect to sso.example.com/login.
Frontend Server (f.com) | |---[ReactJS App] | | | |---[GET Request]---> Backend Server (b.com) | | | |--[Redirect]---> Proxy Endpoint (b.com/proxy) | | | |---[Server-Side Redirect]---> SSO Server (sso.example.com) | └---[Authentication Flow Continues Without CORS Error]
This solution avoids the CORS issue because the redirect is handled server-side, and the client does not directly interact with sso.example.com.
Alternatively, you can use a React library that handles the SSO login flow for you, such as @react-oauth/google or react-social-login-buttons. These libraries simplify the process of implementing SSO in your React application.
Lastly, you can also adjust the flow to use OAuth2 directly on the backend, eliminating the need for a proxy endpoint. The backend can exchange the code received from the client for an access token and refresh token, which can then be used to fetch user information from the SSO provider.
type UserData struct { Email string Name string Token *oauth2.Token } var googleOauthConfig = &oauth2.Config{ RedirectURL: "http://localhost:1323/oauth/callback", ClientID: "your-client-id.apps.googleusercontent.com", ClientSecret: "your-secret", Scopes: []string{"profile", "email"}, Endpoint: google.Endpoint, } func GetUserDataFromGoogle(code string) (UserData, error) { var userData UserData token, err := googleOauthConfig.Exchange(context.Background(), code) if err != nil { return userData, fmt.Errorf("code exchange wrong: %s", err.Error()) } response, err := http.Get("https://www.googleapis.com/oauth2/v2/userinfo?access_token=" + token.AccessToken) if err != nil { return userData, fmt.Errorf("failed getting user info: %s", err.Error()) } defer response.Body.Close() contents, err := io.ReadAll(response.Body) if err != nil { return userData, fmt.Errorf("failed read response: %s", err.Error()) } err = json.Unmarshal(contents, &userData) userData.Token = token return userData, nil }
This approach bypasses the CORS issue and simplifies the solution.