Prevent duplicate accounts using magic links in Firebase

Let's assume that a user introduces his email on your site to get a magic link back. The following function executes after the Firebase server receives the request:

javascript
exports.sendMagicLink = functions.https.onRequest((request, response) => {
    
    return cors(request, response, async () => {
        
        // You get the email of a user who wants to get a magic link
        let email = request.body.email;
        
        // You need to generate a unique identifier (UID) for the user
        // You could use the email as UID, but since you want to create 
        // data in the Firebase database, you need to prevent branches 
        // with '.' and special symbols.
        // It's better to create a new UID for that user from scratch
        // See an example of this function at the end of the article
        let uid = getUniqueId();
        
        // At this point, you can create a custom token for the user
        let token = await admin.auth().createCustomToken(uid);
        
        // Now you have the magic link to send back to the user
        let magicLink = `http://${url}/token=${token}`;
        
        // ...
        
    }
    
}

If a user logs out from your site and wants to get the magic link again, later on, you'll need to resend the same magic link to that user.

Before sending the link back, you need to check if the user got the magic link in the past to prevent the creation of duplicate accounts.

Each user is associated with a magic link.

javascript
exports.sendMagicLink = functions.https.onRequest((request, response) => {
    
    return cors(request, response, async () => {
        
        // You get the email of a user who wants to get a magic link
        let email = request.body.email;
        
        // You declare an empty UID variable
        let uid;
        
        // If the user got the magic link in the past, you get his UID
        // You can use getUserByEmail() to get a user
        // If the email is not found, the function will throw an error
        try{
            
            let firebaseUser = await admin.auth().getUserByEmail(email);
            
            uid = firebaseUser.uid;
            
        }
        // Otherwise, you generate a new unique UID
        catch(e){
            
            uid = getUniqueId();
            
        }
        
        // At this point, you can create a custom token for the user
        let token = await admin.auth().createCustomToken(uid);
        
        // Now you have the magic link to send back to the user
        let magicLink = `http://${url}/token=${token}`;
        
        // ...
        
    }
    
}

Here is getUniqueId() function:

javascript
const getUniqueId = () => {
    
    let wwww = Math.random().toString(32).slice(-4);
    let xxxx = Math.random().toString(32).slice(-4);
    let yyyy = Math.random().toString(32).slice(-4);
    let zzzz = Math.random().toString(32).slice(-4);
    
    return wwww + xxxx + yyyy + zzzz;
    
}

Feel free to create your function. But keep in mind that it needs to return a random and unique number to avoid collisions.

Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.