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

Discovering the destination link of a website while utilizing GM_xmlhttpRequest

Picture yourself browsing a webpage called "www.yourWebsite.com" and utilizing userscripts in Tampermonkey to extract data from another site using the GM_xmlhttpRequest function. As you make requests with the GM_xmlhttpRequest function to visit "exampleWe ...

Error occurred during service communication in the Kubernetes environment

Currently, I am in the process of setting up a microservices architecture using Kubernetes. In this setup, I have two main services: an authentication module and a client service. The client service sends requests to the authentication module to retrieve u ...

Navigating the terrain of multiple checkboxes in React and gathering all the checked boxes

I am currently developing a filter component that allows for the selection of multiple checkboxes. My goal is to toggle the state of the checkboxes, store the checked ones in an array, and remove any unchecked checkboxes from the array. Despite my attemp ...

Angular JS: Extracting the header from a CSV file

Just getting started with angular JS and I have a question. I need to take a CSV file from the user as input and then send it to the controller when they click submit. <button class="btn btn-primary" type="submit" ng-click="Input(File)">Submit</ ...

What could be the issue with my JSON data stream?

Trying to set up the Fullcalendar JQuery plugin with a JSON feed has been a bit of a challenge. The example provided with the plugin works perfectly, so it seems like there might be an issue with my own feed. Here is the output from the working example JS ...

Stopping an endless loop when retrieving data from localStorage in next.js

While working with fetching data from localStorage in the useEffect Hook, I encountered an interesting behavior. When I set the dependency array to [] (blank), the data is fetched successfully but new data is not retrieved until the page is refreshed. Howe ...

Dynamic resizing in NextJs does not trigger a re-render

My goal is to dynamically pass the width value to a component's styles. Everything works fine on initial load, but when I resize the window, the component fails to re-render even though the hook is functioning as intended. I came across some informat ...

A versatile jQuery function for extracting values from a :input selector

Is there a universal method in jQuery to retrieve the value of any :input element? I pose this question because I have a webpage containing select and checkbox inputs, as seen in the code below: for (var i = 0; i < arguments.length; i++) { ...

Concealing overflow for text content through CSS styling

I am currently working with an element that contains both an image and text. View the Fiddle here Note: To see the full grid, resize the preview accordingly. The CSS I have written is as follows: .gridster .gs-w .item{ position: relative; wi ...

Manipulating arrays in a JSON file with JavaScript

Struggling with adding a new value to an array stored in a file.json? The array currently contains ["number1", "number2"], and you want to add "number3". However, attempts to define a variable in the JavaScript file containi ...

Unexpected outcomes from the Jquery contains method

Take a look at this example: http://jsfiddle.net/SsPqS/ In my HTML, there's a div with the class "record" to which I've added a click function. Within the click function, I have the following code snippet (simplified): $(".record").click(funct ...

CSS or jQuery: Which is Better for Hiding/Showing a Div Within Another Div?

Show only class-A at the top of the page while hiding all other classes (x,x,c). Hide only class-A while showing all other classes (x,x,c). Is it possible to achieve this? <div class="x"> <div class="y"> <div class="z"&g ...

Issue: Failed to retrieve configuration settings due to the inability to connect with the query-engine-node-api library in Prisma and nextjs framework

In my setup, I am using a fresh project in Next.js with Prisma and a Supabase database on Ubuntu. When running the Prisma push and generate commands in my project, I encounter the same error with both npm and yarn even though I have run all Prisma commands ...

Ensuring session data is updated when saving a mongoose model

I am facing a challenge with updating express session data in the mongoose save callback. Is there a way to access and modify the session data from within line 4 of the code? app.get('/', function(req, res){ var newModel = new Model(somedata); ...

Extracting and retrieving data using JavaScript from a URL

After reviewing some code, I am interested in implementing a similar structure. The original code snippet looks like this: htmlItems += '<li><a href="show-feed.html?url=' + items[i].url + '">' + items[i].name + '& ...

What is the most effective method for generating dial images through programming?

Currently, I am in the process of creating a website that makes use of variously sized and styled dials to indicate progress. The filled portion of the dial represents how close an item is to being 100% complete. I am seeking a universal solution that wil ...

revalidatePath function in NextJS does not reset the form

In my client component, I have a form that triggers a server action when submitted. Here is the code snippet: <Form {...form}> <form ref={ref} onSubmit={form.handleSubmit(onSubmit)} > Additionally, function onSubmit(data: ...

Use Node.js with Selenium and WebdriverIO to simulate the ENTER keypress action on

I have put in a lot of effort trying to find the solution before resorting to asking this question, but unfortunately I have not been successful. All I need to know is how to send special characters (such as the enter key and backspace) with Node.js using ...

The Joi validate() function will return a Promise instead of a value when used within an asynchronous function

Trying to understand how async functions and the Joi.validate() function behave. Below is a function used for validating user input. const Joi = require("joi"); const inputJoiSchema= Joi.object().keys({ name: Joi.string(), email: Joi.string().require ...

Displaying tooltips dynamically for newly added elements all sharing a common class in React

I'm facing an issue with the primereact tooltip component from . Everything seems to be working fine except for the target property. When I have multiple elements on a page with the same class, the tooltip works as expected. However, when I add a new ...