firebaseでcookieを使おうとしてハマった話


最初に結論

cookie使うときは __session ってkey以外は切り捨てられるぞ気をつけろ!

やろうとしたこと

こんなかんじの実装?


const functions = require('firebase-functions');
const express = require('express');
const cookieParser = require('cookie-parser');
const admin = require('firebase-admin');
const firebase = require('firebase/auth');
admin.initializeApp({...});
firebase.initializeApp({...});

const app = express();
app.use(cookieParser());

// サインイン処理
function signin(email, pass) {
    return new Promize((resolve, reject) => {
        firebase.auth().signInWithEmailAndPassword(email, pass)
        .then((result) => { firebase.auth().onAuthStatechanged(resolge); })
        .catch(reject);
    });
};

const expiresIn = 60*60*24*5*1000; // 5days
app.post('/signin', (req, res) => {
    var email = req.body.email;
    var pass = req.body.pass;

    signin(email, pass)
    .then((user) => {
        user.getIdToken()
        .then((token) => {
            admin.auth().createSessionCookie(token, {expiresIn})
            .then((sessionCookie) => {
                // cookieに詰め込む
                res.cookie('session', sessionCookie, {maxAge: expiresIn});
                res.redirect('/mypage');
        });
    })
    .catch((error) => {
        res.send('error:'+error);
    });
};

app.get('/mypage', (req, res) => {
    var sessionCookie = req.cookies.session;
    console.log('sessionCookie:'+sessionCookie); // cookieから取り出した内容をとりあえず表示してみる

    // cookieの情報から認証確認
    admin.auth().verifySessionCookie(sessionCookie, true)
    .then((decodedClaims) => {
        var uid = decodedClaims.uid;
        res.send('signed in by uid('+uid+')'); // singin してるのはこのuidさんだよ
    })
    .catch((error) => {
        res.send('error:'+error);
    });
};

exports.app = functions.https.onRequest(app);

ローカルでcookie認証できてることを確認する

firebase serve してlocalhost:5000にアクセス
email&passで認証して、その認証がキープされてることが確認できた!

よし、これでOKだろう!

さぁ firebase deploy して、publicな環境で確認してみよう!

が、ダメ!

おかしいな?

localではできたのにdeployした先ではcookieが空っぽになってるやん!
firebaseのドキュメントを参考に作ったんだけどなぁ

実はこんな罠があった

結構な時間悩んでいたけど、実は罠が潜んでいた
ドキュメントの実装例には session というkeyでcookieに情報を詰め込んでいたが、これが NG

__session というkey以外の情報は削除されてしまうようだった
参考:https://firebase.google.com/docs/hosting/manage-cache?hl=ja#using_cookies

へぇ~localとpublicで挙動違うんだなぁ

修正版


const expiresIn = 60*60*24*5*1000; // 5days
app.post('/signin', (req, res) => {
    var email = req.body.email;
    var pass = req.body.pass;

    signin(email, pass)
    .then((user) => {
        user.getIdToken()
        .then((token) => {
            admin.auth().createSessionCookie(token, {expiresIn})
            .then((sessionCookie) => {
                // cookieに詰め込む
                res.cookie('__session', sessionCookie, {maxAge: expiresIn});// ★keyを__sessionにした
                res.redirect('/mypage');
        });
    })
    .catch((error) => {
        res.send('error:'+error);
    });
};

app.get('/mypage', (req, res) => {
    var sessionCookie = req.cookies.__session;// ★keyを__sessionにした
    console.log('sessionCookie:'+sessionCookie); // cookieから取り出した内容をとりあえず表示してみる

    // cookieの情報から認証確認
    admin.auth().verifySessionCookie(sessionCookie, true)
    .then((decodedClaims) => {
        var uid = decodedClaims.uid;
        res.send('signed in by uid('+uid+')'); // singin してるのはこのuidさんだよ
    })
    .catch((error) => {
        res.send('error:'+error);
    });
};

これでなんとかcookieから情報を引き出せるようになったぞヤッター
※ 実装例は動作確認してないですすみません。