kwoxer
kwoxer

Reputation: 3833

Store MSAL logged-in users and precheck them before doing a request on node.js web app

In my node project I have the following basic code to connect to Azure via a token. The login/logout works great together with our Azure:

const express = require("express");
const msal = require('@azure/msal-node');
const SERVER_PORT = process.env.PORT || 3000;
const config = {
    auth: {
        clientId: "XXX",
        authority: "https://login.microsoftonline.com/common",
        clientSecret: "XXX"
    },
    system: {
        loggerOptions: {
            loggerCallback(loglevel, message, containsPii) {
                console.log(message);
            },
            piiLoggingEnabled: false,
            logLevel: msal.LogLevel.Verbose,
        }
    }
};
const pca = new msal.ConfidentialClientApplication(config);
const app = express();

app.get('/', (req, res) => {
    res.send("<a href=\"login\">Login</a> <a href=\"logout\">Logout</a>");
});
app.get('/dashboard', (req, res) => {
    // check here for valid token...
});
app.get('/login', (req, res) => {
    const authCodeUrlParameters = {
        scopes: ["user.read"],
        redirectUri: "http://localhost:3000/redirect",
    };
    pca.getAuthCodeUrl(authCodeUrlParameters).then((response) => {
        res.redirect(response);
    }).catch((error) => console.log(JSON.stringify(error)));
});
app.get('/logout', (req, res) => {
    res.redirect('https://login.microsoftonline.com/common/oauth2/v2.0/logout?post_logout_redirect_uri=http://localhost:3000/');
});
app.get('/redirect', (req, res) => {
    const tokenRequest = {
        code: req.query.code,
        scopes: ["user.read"],
        redirectUri: "http://localhost:3000/redirect",
    };
    pca.acquireTokenByCode(tokenRequest).then((response) => {
        console.log("\nResponse: \n:", response);
        res.sendStatus(200);
    }).catch((error) => {
        console.log(error);
        res.status(500).send(error);
    }); 
});
app.listen(SERVER_PORT, () => console.log(`Msal Node Auth Code Sample app listening on port ${SERVER_PORT}!`))

But how to properly check after that logging in if the token is still valid?

So the question is, how can I be save that the user on /dashboard has still a valid token or is logged in?

app.get('/dashboard', (req, res) => {
    // check here for valid token...
});

At the end I need a node.js application that:

Can I do all that in node.js or better doing that in client-side? But am I then reducing the security?

Upvotes: 1

Views: 1876

Answers (3)

kwoxer
kwoxer

Reputation: 3833

Using the silent-flow was a good idea. It works great on my example.

https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/samples/msal-node-samples/standalone-samples/silent-flow

This works with the PublicClientApplication and acquireTokenSilent works also as expected.

Upvotes: 0

kwoxer
kwoxer

Reputation: 3833

I found a kind of dirty way to solve my issue. Could you maybe tell me if that is a proper way? Also my solution is not safe as the user could change the client-side JS code and ignore the user auth.

Create HTML file for /dashboard:

app.get('/dashboard', function(req, res) {
      res.sendFile(__dirname + "/" + "index.html");
});

and here using this JS code:

var headers = new Headers();
var bearer = "Bearer " + "ey...........Ac"; // <---- accessToken
headers.append("Authorization", bearer);
var options = {
        method: "GET",
        headers: headers
};
var graphEndpoint = "https://graph.microsoft.com/v1.0/me";

fetch(graphEndpoint, options)
    .then(resp => {
         // when error redirect to ... otherwise do log:
         console.log(123);
    });

on the <---- accessToken putting a valid token and it works. Only when token is valid the console.log is done.

So this works, but as I said, if the user is manipulating the code he can still see the page. Also the page is loading until the script is fired. So I cannot see a real value on this. This should happen on server-side somehow. Any idea?

Upvotes: 0

sgonzalez
sgonzalez

Reputation: 836

Once you get your authentication result the first time, this should have received tokens if authentication was successful. You should be able to parse the Id token to get information about the user. You can then use that information to create a session via the web framework that you are using. The session can be used thorough out the web app to give you information like if the user is authenticated or not, how long they are authenticated for, and what they have permission to access. Usually web frameworks will create a cookie with a session id so that requests coming in will be able to have session information, and the user won't have to authenticate every time.

If the session expires, you can try acquiring a token silently (without prompting the user) by using the token cache that is part of MSAL. When you call acquire token silent, MSAL will automatically check if the access token is valid, if not it will try to refresh the access token via the refresh token. If neither are valid, they will return an error. At this point you can fall back to prompting the user again to authenticate (via the code that you have already shared).

Upvotes: 1

Related Questions