Search code examples
authenticationpassport.jskoa

koa-passport w/ passport-steam: ctx.isAuthenticated() always false


I am using koa-passport with passport-steam to Authenticate users with SteamID. ctx.isAuthenticated() is always false, despite correctly logging in through Steam. I have been looking at plenty of other SO questions and guides and google results, and the issue is common, but always due to idiosyncratic errors in someones code that doesn't apply to mine. There is some other idiosyncratic issue plaguing my code apparently but I can't find it. Most of the passport related code is practically copy-pasted from tutorials/docs/examples. My middle ware has correct ordering and as far as I can tell its not a sessions configuration issue.

const Koa = require("koa");
const session = require("koa-session");
const Router = require("@koa/router");
const views = require("koa-views");
const passport = require("koa-passport");
const SteamStrategy = require("passport-steam").Strategy;
const bodyparser = require("koa-bodyparser");

const root = "http://localhost:3000";
const app = new Koa();
const router = new Router();

passport.serializeUser((user, done) => {
    console.log("Serializing:", user);
  done(null, user);
});

passport.deserializeUser((obj, done) => {
    console.log("Deserializing:", obj);
  done(null, obj);
});

passport.use("steam", new SteamStrategy({
        returnURL: root + "/auth/steam/return",
        realm: root,
        apiKey: "---"
    },
    function(identifier, profile, done) {
        process.nextTick(function () {
            let identifie = identifier.match(/\/id\/(\d+)/)[1];
            profile.id = identifie
            console.log("Returned from Steam:", profile);
            return done(null, profile);
        });
    })
);

app.on("ready", () => {
    console.log('ready');
});

app.on("error", (err, ctx) => {
    console.log("ERR:", err);
});

const CONFIG = {
    key: 'koa.sess',
    maxAge: 10000,
    secure: true
} 
//I have tried tons of cookie settings including using default
//because a lot of people in the koa-passport issues seem to have solved
//their similar problem by changing session settings, but I've had no such luck
app.keys = ['session_secret'];
app.use(session(CONFIG, app));
app.use(bodyparser());
app.use(passport.initialize());
app.use(passport.session());

app.use(views("views", { 
            map: { 
                ejs: "ejs" 
            }
        })
);

//A shoddy attempt at middleware just to test. But ctx.isAuthenticated always returns false.
app.use(async (ctx, next) => {
    if (ctx.isAuthenticated()) {
        console.log("Hey! You're authenticated");
    }
    return next()
});

app.use(router.routes());


router.get("/", async (ctx, next) => {
    await ctx.render("howdy.ejs");
});

router.get("/auth/steam", async (ctx, next) => {
    console.log("Trying to auth");  
    return passport.authenticate('steam', { failureRedirect: "/fail" })(ctx);
});

router.get("/auth/steam/return", async (ctx, next) => {
    passport.authenticate('steam', { failureRedirect: "/fail", successRedirect: "/text" })(ctx);
    ctx.redirect("/text");
});

router.get("/fail", async (ctx, next) => {
    await ctx.render("fail.ejs");
});

router.get("/text", async (ctx, next) => {
    console.log(`
    Auth: ${ctx.isAuthenticated()},
    Unauth: ${ctx.isUnauthenticated()},
    User:
    `);
    console.log(ctx.state.user);
    console.log(ctx.req.user);
    if (ctx.state.user) {
        await ctx.render("success.ejs");
    } else {
        await ctx.render("fail.ejs");
    }
});


app.listen(3000);

Let's walk through an example interaction: You click a button on the index to take you to /auth/steam. Trying to auth prints in (my) console, you are redirected to Steam. You login (after the login you'll be redirected to /text).

Trying to auth
   
    Auth: false,
    Unauth: true,
    User:
    
undefined //ctx.state.user, this is how koa-passport should expose the authenticated user.
undefined //ctx.req.user, as a test. I don't expect it to be defined but I see it mentioned in some docs.
Returned from Steam: {YOUR PROFILE!}
Serializing: {YOUR PROFILE!}

my test print of information showing Auth/Unauth/User is printed before the profile, i assume this is because of some kind of async racing. To be sure, you'll reload the page (/text) to get this kind of information again:

    Auth: false,
    Unauth: true,
    User:
    
undefined
undefined

No change!


Solution

  • You've probably moved on from this by now, but your question gave me what I needed to get Steam authentication working in my project, so I thought I'd share what I found.

    I didn't run your code example directly, but I think these are the 2 issues.

    First, your /auth/steam/return endpoint needs to be updated. It should look like this:

    router.get("/auth/steam/return", async (ctx, next) => {
        return passport.authenticate('steam', { failureRedirect: "/fail", successRedirect: "/text" })(ctx);
    });
    

    Second, I had trouble with the session config. Specifically secure: true didn't work for me as I was testing over an unsecured connection (http). There may be an exception for localhost, but if not, changing CONFIG worked for me. I also changed the maxAge as it was set to 10 seconds or 10,000 ms.

    const CONFIG = {
        key: 'koa.sess',
        maxAge: 86400000,
        secure: false
    }