reactjsexpresspassport.jsexpress-sessionpassport-saml

Passport-js: Express-Session gets regenerated when callback endpoint is called


I am trying to use passport-saml to authenticate users with a SAML IdP. As Frontend I am using React JS with Vite and as Backend I am using express.js with express-session as session manager.

My problem is that I use a separate authentication system for my users in addition to Passport. This authentication system already uses express-session to store various data about the user sessions, including whether the user is currently authenticated and which user it is. My goal now is to connect this authentication system to that of passport-saml so that my users can log in through my authentication system and add another authentication method to access their account through passport-saml. Unfortunately, this is what happens:

my passport Strategy Config looks like this:

passport: {
        strategy: 'samlStrategy',
        saml: {
            callbackUrl: process.env.BACKEND_BASE_URL + "/api/eid-saml/callback",
            entryPoint: // the saml idp i am using,
            issuer: // my web app's name,
            cert: // idp cert,
            privateKey: // my private key,
            passReqToCallback: true
        }
    }

My Strategy itself is pretty simple:

const samlStrategy = new Strategy(
    config.passport.saml,
    function (req, profile, done) {
        try {
            return done(null, profile);
        } catch(error) {
            return done(null, false, "ErrorMessage:" + error);
        }
    }
)

And finally here are my login and callback endpoints:

router.get("/login", function(req, res, next) {
        console.log(req.session);
        passport.authenticate("samlStrategy", {
            successRedirect: '/api/eid-saml',
            failureRedirect: '/api/eid-saml/login',
            session: false
        })(req, res, next);
    }
);

router.post("/callback",
    function(req, res, next) {
    console.log(req.session);
    res.status(200).send("Authentifiziert!");
    }
);

From the frontend I am redirecting my users to my login endpoint using window.location.href to start the SAML login procedure. If I now compare the request session that I get on my login endpoint:

Session {
  cookie: {
    path: '/',
    _expires: 2023-06-03T12:47:32.166Z,
    originalMaxAge: 3600000,
    httpOnly: true,
    secure: false,
    domain: null,
    sameSite: true
  },
  isAuthenticated: true,
  userName: //a user name,
  userId: // a user id,
}

with the one that I get when the callback endpoint is called:

Session {
  cookie: {
    path: '/',
    _expires: 2023-06-03T12:48:09.301Z,
    originalMaxAge: 3600000,
    httpOnly: true,
    secure: false,
    sameSite: true
  }
}

I can see that the properties coming from my own authentication system are missing now. That way, I am not able to link the data coming from the SAML response with the data coming from my own authentication system. I am not able to understand why the session is working on my login endpoint but not on my callback endpoint since both endpoints are available over the same domain. Is there any way to resolve this issue or am I missing something that prevents me from reading the session data in my callback endpoint?


Solution

  • I was actually able to resolve the problem in the meantime. I think the problem occurred because the Identity Provider executed a redirect to the Callback endpoint of my Service Provider implementation directly on the server side. Since the cookie that contained the session ID was only available in the cookie storage of the user agent, the request to my callback endpoint did not contain the cookie information anymore. My solution was:

        const assertSaml = (req, res) => {
            let samlOptions = JSON.parse(unescape(req.body?.samlOptions))
            sp.post_assert(idp, samlOptions, (err, saml_response) => {
                    if (err != null) {
                        return res.status(500).send("ServerError: " + err);
                    } else {
                        // do something with req.session and saml_response
                        return res.status(200).send("Already existing user session and SAML session information are now linked together, nice.");
                    }
                }
            );
        }