Limit sign in and social sign in to specific domains

Hi I have an auth0 application where i need to only allow sign in for a google auth users on a specific domain.

I’ve added actions to reject emails not aligned with those domains for the Pre User Registration, Post Login and Post User registration triggers but nothing happens. I can still login using any google auth account.

I scaled back to simply log data, but nothing is showing in the actions real time logs.

Please assist.

Hi @david33,

You can use the Post Login trigger to test for the connection and the email. Since they only work for database connections, the Pre and Post User Registration triggers won’t be fired.

This is how the action should look (modify it for your specific use case):

exports.onExecutePostLogin = async (event, api) => {
 if (event.connection.id === "{google connection id}") {
   let split = event.user.email?.split('@');
   if (!split) { // check if the split was done successfully
     return;
   }

   let domain = split[1];
   if (domain === "{domain you need to check against}") {
     api.access.deny("Access denied");
   }
 }
};

After creating the action, add it to the flow and save it.

If you have any other questions, feel free to reach out.

Have a good one,
Vlad

Hi Vlad. Thanks for the quick turn around.

I do have a similar implementation. I just have 2 concerns because I’m using I’m using Auth0AuthProvider from ra-auth-auth0 and Auth0Client from @auth0/auth0-spa-js in my react SPA

  1. The user record is still created. One consideration i had was to call a management API endpoint to trigger a delete user operation to resolve this. Is there a better approach you’d suggest?

  2. Because the user record is created the auth-callback on the login error causes a loop when the user tries to sign in again. In the backend when i delete the user and try to sign in, it goes to the login page. Is there a way to skip this step? By pass the callback page in this instance and revert to the login page with the error?

Hi again @david33,

  1. The standard and recommended way to handle this is to use the Management API to delete the user within the same Action.
// rest of the code

if (domain === "{domain you need to check against}") {

  // 1. Delete user
  const ManagementClient = require('auth0').ManagementClient;

  const management = new ManagementClient({
      domain: event.secrets.domain,
      clientId: event.secrets.clientId,
      clientSecret: event.secrets.clientSecret,
  });

  try {
    await management.users.delete({id : event.user.user_id})
  } catch (e) {
    console.log(e)
    // Handle error
  }

  // 2. Deny user access
  api.access.deny("Access denied");
}
  1. The redirect loop you’re seeing is a front-end concern. Your React SPA needs to be updated to correctly handle the error Auth0 sends back to your callback URL after access is denied.

You need to modify the component that handles the /auth-callback route to check for errors in the URL.

Here is a conceptual example of what your callback component might look like.

// src/AuthCallback.js (or wherever you handle the redirect)

import React, { useEffect, useState } from 'react';
import { useAuth0 } from '@auth0/auth0-react'; // Or the equivalent from ra-auth-auth0
import { useNavigate } from 'react-router-dom';

const AuthCallback = () => {
  const [error, setError] = useState(null);
  const navigate = useNavigate();
  const { handleRedirectCallback } = useAuth0(); // This might be abstracted by ra-auth-auth0

  useEffect(() => {
    const processAuth = async () => {
      // Check the URL for error parameters from Auth0
      const params = new URLSearchParams(window.location.search);
      const authError = params.get('error');
      const errorDescription = params.get('error_description');

      if (authError) {
        // If an error is found, set it in the state to display to the user
        setError(errorDescription || authError);
      } else {
        // If no error, proceed with the normal login flow
        try {
          await handleRedirectCallback();
          // Redirect to the intended page after successful login
          navigate('/'); 
        } catch (e) {
          setError(e.message);
        }
      }
    };

    processAuth();
  }, [handleRedirectCallback, navigate]);

  if (error) {
    return (
      <div>
        <h1>Login Error</h1>
        <p>There was a problem signing you in:</p>
        <p><i>{error}</i></p>
        <button onClick={() => navigate('/login')}>Try Again</button>
      </div>
    );
  }

  return <div>Loading...</div>; // Or your standard loading spinner
};

export default AuthCallback;

Proactive Guidance

  • User Experience: The api.access.deny("reason") message is passed to the front end in the error_description query parameter. You can use this to display a friendly and informative error to the user, like in the React example above, so they understand exactly why their login was rejected.
  • Rate Limits: Remember that calling the Management API from an Action counts against your tenant’s rate limits. For most applications, this pattern is wonderful. However, if you expect a high volume of blocked login attempts, it’s a factor to be aware of.

If you have any further questions, feel free to reach out!

Have a good one,
Vlad

Thanks for the helpful tips here Vlad. I’ll tinker with the front end bit at a later time but thanks for confirming re setting the backend up for the deletes!