Navigating with NextJS to a personalized URL and managing the feedback from an external application

I'm currently in the process of developing an application that involves redirecting users to a specific URL, prompting them to open an app (with a url starting with zel:), and then sending a request back to my server. Here's the envisioned user journey:

  1. User clicks on the login button.
  2. User is directed to open an app and complete the sign-in process.
  3. The app sends a callback message to my server confirming the completion of the sign-in.
  4. I verify the user's sign-in status and then redirect them to a new path (e.g., /afterlogin).

I'm unsure about the steps needed to achieve this. Can anyone provide guidance?

Below is the code snippet I've been working on:

// pages/login.js

import axios from 'axios';
import { useRouter } from 'next/router';

export default function Login() {
    const router = useRouter();
    const handleClick = () => {
        axios.get('https://api.runonflux.io/id/loginphrase').then(response => {
            if (response.data.status === 'success') {
                var loginPhrase = response.data.data;
                if (loginPhrase) {
                    router.push(`zel:?action=sign&message=${loginPhrase}&callback=${process.env.DOMAIN}api/validateSignature`);
                }
            }
        });
    }
    return (
        <div>
            <button onClick={handleClick}>Login</button>
        </div>
    )
}

This section represents the login page where users will initiate the sign-in process by clicking the login button, fetching a phrase through an API request, and getting redirected to authorize via an external app.

// pages/api/validateSignature.js

export default function handler(req, res) {
    if (req.method == 'GET') {

    }
    var url = "https://api.runonflux.io/id/verifylogin";
    var axios = require('axios');
    var data = JSON.stringify({
        "loginPhrase": req.body.message,
        "signature": req.body.signature,
        "zelid": req.body.address
    });
    var config = {
        method: 'post',
        url: url,
        data: data
    };
    axios(config)
        .then(function (response) {
            console.log(response.data);
        })
        .catch(function (error) {
            console.log(error);
        });
    res.status(200).json({ name: 'John Doe' })
}

This script manages the callback from the app.

A visual representation of the user flow can be viewed in this video - https://i.stack.imgur.com/Fn4j5.jpg

Answer №1

My solution involved incorporating MongoDB to assist me in handling this task.

I have set up a redirect to a waiting page, which periodically checks MongoDB every 3 seconds to monitor if the customer has completed the sign-in process:

// pages/waiting/[loginPhrase.js]
import React, { useState, useEffect } from 'react';
import { useRouter } from 'next/router'

const WaitingPage = () => {
    const router = useRouter();
    const { loginPhrase } = router.query
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        const checkApi = async () => {
            try {
                const response = await fetch('/api/checkMessage', {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ "loginPhrase": loginPhrase }),
                });
                const json = await response.json();
                console.log(json.data[0]);
                if (json.data[0] !== undefined) {
                    const responseVerify = await fetch('https://api.runonflux.io/id/verifylogin', {
                        method: 'POST',
                        body: JSON.stringify({ "address": json.data[0].address, "message": json.data[0].message, "signature": json.data[0].signature }),
                    });
                    const respJson = await responseVerify.json();
                    console.log(respJson);
                    if (respJson.status === 'success' && respJson.data.message == 'Successfully logged in') {
                        router.push(`/success`);
                    }
                }
            } catch (err) {
                setLoading(false);
                console.error(err);
            }
        };

        const intervalId = setInterval(checkApi, 3000);
        return () => clearInterval(intervalId);
    }, []);


    return (
        <div>
            {loading ? (
                <p>Loading...</p>
            ) : data ? (
                <p>Data received: {JSON.stringify(data)}</p>
            ) : (
                <p>No data received</p>
            )}
        </div>
    );
};

export default WaitingPage;

I also created two API calls - one for the app callback to insert data into MongoDB:

// pages/api/signedMessage.js
import clientPromise from "../../lib/mongodb";

export default async function handler(req, res) {
    const client = await clientPromise;
    const db = client.db("zel_login");
    if (req.method === "POST") {
        if (!req.body.address || !req.body.message || !req.body.signature) {
            return res.status(400).json({ status: 400, message: "Bad Request" })
        }
        let messageObject = {
            createdAt: new Date(new Date().toISOString()),
            address: req.body.address,
            message: req.body.message,
            signature: req.body.signature
        }
        let newMessage = await db.collection("signed_messages").insertOne(messageObject);
        res.json(newMessage);
    }
}

The second API call attempts to locate the loginPhrase and then verifies it with an additional API call:

// pages/api/checkMessage.js
import clientPromise from "../../lib/mongodb";

export default async function handler(req, res) {
    const client = await clientPromise;
    const db = client.db("zel_login");
    if (req.method === "POST") {
        const message = await db.collection("signed_messages").find({ "message": req.body.loginPhrase }).toArray();
        res.json({ status: 200, data: message });
    }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Testing the screen size automatically using Javascript

Hello everyone, I've implemented a JavaScript code that triggers an image to slowly appear and darken the background when a link is clicked. However, on an iPad, the background doesn't completely turn black as intended. The CSS specifies that the ...

What could be causing the content in my select box to change only when additional select boxes are introduced?

When working with a form in next.js and using select boxes from material UI, I encountered an issue. The number of select boxes should change based on user input, but when I modify the value inside a select box, the displayed text does not update until I a ...

How to change the focus on a Material UI input field

I am facing an issue with resetting/clearing an input field using a button click: Take a look at the code here for reference. const searchInput = useRef(null); const clearInput = () => { searchInput.current.value = ''; searchInput ...

Blur Event Triggered in Primefaces Editor

My current setup involves using JSF Mojarra 2.2.8 with PrimeFaces 5.1, where I utilize a PrimeFaces editor for text input. I am looking to automatically upload the entered text via ajax. However, the editor only supports an onchange event. I'm seekin ...

Utilizing jQuery and AJAX for submitting multiple POST requests

Experiencing a problem with posting data via AJAX using a drag and drop interface. The data is being sent to the POST URL as intended, but there's a recurring issue where the POST request occurs twice, causing the processing URL to handle the data aga ...

I'm struggling to get Router.push to redirect me on Next.js with an Express server

I'm currently working on creating a simple login page with a dashboard using an Express server and Nextjs. The goal is for users to be redirected to the dashboard after successfully logging in with their credentials. However, it seems that when I use ...

Next-auth does not automatically redirect users once they have successfully logged in using their GitHub credentials

After carefully reviewing the documentation multiple times, I am still encountering an issue where users who successfully log in via GitHub are not automatically redirected to the dashboard on the '/' page when using next-auth. I suspect that the ...

Tips for effectively handling a prop in an HTML form using Vue.js and avoiding infinite loops with a computed property

I have a Vue.js form for signing up that features numerous similar fields. From my understanding, I should initialize the values as props rather than objects or arrays (since they will be pass-by-value). My approach involves using a computed property with ...

Tips for sending a URL in form-data as a file with JavaScript or Axios

Currently, I am using Vue.js and Axios to send form data to a specific link. However, I encountered an issue where the file is not being sent and I am receiving an error message. The parameter 'file' had the following problems: file transferred w ...

Implementing dynamic data binding in JavaScript templates

I've been experimenting with jQuery and templates, and I managed to create a basic template binding system: <script type="text/template" id="Template"> <div>{0}</div> </script> Furthermore... var buffer = ''; v ...

What methods can be used to defer the visibility of a block in HTML?

Is there a way to reveal a block of text (h4) after a delay once the page has finished loading? Would it be necessary to utilize setTimeout for this purpose? ...

Creating a multi-dimensional array using information from a database

I have a unique challenge where I am utilizing a template that generates a menu with a specific structure. In my database, I have various menus stored and I've successfully retrieved them. However, the issue arises when I need to figure out a way to d ...

Can you explain the distinction between using useContext and Redux?

Can you explain the distinction between useContext and Redux? Is Redux similar to using useContext? Do I no longer require useContext when implementing Redux in my project? ...

An issue encountered in the getServerSideProps function of NextJS when using axios

When working on the main page (index.js file), I utilize the getServerSideProps function export async function getServerSideProps(context) { axios.defaults.headers.common['Lang'] = context.locale try { const response = await axios ...

Import objects into THREE.js using OBJLoader, convert to Geometry, apply transformations, and finally convert to BufferGeometry

Trying to figure out why the geometry loaded with OBJLoader cannot be smoothly shaded. var loader = new THREE.OBJLoader(manager); loader.load('/manmodel/js/man.obj', function (object, materials) { console.log(object); console.log(materia ...

An error occurred: Cannot access the 'splice' property of an undefined value

//Screenshot <div v-for='(place) in query.visitPlaces' :key="place.name"> <div class="column is-4 is-narrow"> <b-field label="Nights"> <b-input type="text" v-model="place.nights" placeho ...

How to activate the menu in AngularJS

Within my application, I have a header that contains various menu items. These menu items are fetched from a service and displayed in the header. When hovering over the main list, the submenus appear. My goal is to highlight the parent item as active when ...

The issue of Three.js SkinnedMesh jittering arises when it is distant from the scene's root (0,0,0)

In my current project, I am developing a third-person RPG style game using Three.js and Blender. The terrain in the game world is tiled and loops endlessly in all directions, triggered when the player object approaches defined edges along the z or x-axis. ...

Steps to insert an image object into a table

Note: The image in the database is named "profileImage." I want to create a dynamic image object similar to other objects when I insert this code. { label: "Image", name: "profileImage", } It will display the image endpoint as 3704545668418.PNG and ...

Display a particular div upon clicking a specific link, while concealing the other divs

As a beginner in the world of jQuery and coding, I'm encountering some difficulties that I need help with. My goal is to have the 'Vlogging' link activated and show 'Details 1' when the page loads. Then, upon clicking on either &a ...