Reputation: 3407
How can I set session expiration for a Firebase auth session? By default the session never expires.
I wish for the session to expire after 8 hours of inactivity.
I have read the documentation but cannot figure out how to set session expiration.
My code for signing in the user and performing tasks on sign in and sign out
firebase.auth().signInWithEmailAndPassword(data.email, data.password)
firebase.auth().onAuthStateChanged((user) => {
if (user) {
//Signed in
}else{
//Signed out
}
}
Thanks for all replies! I have tried but cannot seem to get Firebase-admin to work.
Firebase-db.js
const admin = require('firebase-admin')
const databaseConnection = {
serviceAccountFile: './serviceAccount.json',
databaseURL: 'https://myProject.firebaseio.com/'
}
const serviceAccount = require(databaseConnection.serviceAccountFile)
const app = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseConnection.databaseURL
}, 'test')
const database = admin.database(app)
module.exports = database
sessionSignout.js
const functions = require('firebase-functions')
const database = require('../../firebase-db')
const admin = database.admin
exports.sessionSignout = functions
.region('europe-west1')
.pubsub
.schedule('*/15 * * * *')
.timeZone('Europe/Stockholm')
.onRun(async (event) => {
database.ref(`users`)
.once('value', (usersSnapshots) => {
usersSnapshots.forEach((snapshot) => {
const uid = snapshot.key
admin.auth().revokeRefreshTokens(uid)
})
})
}
I get error
Error: function execution failed. Details: Cannot read property 'auth' of undefined
Upvotes: 5
Views: 5010
Reputation: 3407
Thanks for all the answers! I just wanted to share my code for others to use.
I already had code in place to accommodate presence awareness.
index.js
import database from './firebase/firebase' //Firebase setup for client
firebase.auth().onAuthStateChanged((user) => {
//Handle login and redirect
if (user) {
//We are logged in
addPresenceAwarenessListener()
}else{
...
}
}
const addPresenceAwarenessListener = () => {
// Create a reference to the special '.info/connected' path in
// Realtime Database. This path returns `true` when connected
// and `false` when disconnected.
database.ref('.info/connected').on('value', (snapshot) => {
// If we're not currently connected, don't do anything.
if (snapshot.val() == false) {
return
}
const uid = firebase.auth().currentUser.uid
//Push last login/logout to user profile
const userLastLoginOutRef = database.ref(`users/${uid}`)
userLastLoginOutRef.onDisconnect().update({lastLoginOut: firebase.database.ServerValue.TIMESTAMP})
.then(() => { userLastLoginOutRef.update({lastLoginOut: firebase.database.ServerValue.TIMESTAMP}) })
})
}
Session handling - expire sessions after n hours (setting "sessExp" in database)
firebase-db.js - Basic Firebase setup for cloud functions
const admin = require('firebase-admin')
const databaseConnection = {
serviceAccountFile: './my-project.json',
databaseURL: 'https://my-project.firebaseio.com/'
}
const serviceAccount = require(databaseConnection.serviceAccountFile)
const app = admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseConnection.databaseURL
}, 'remindMiNotifier')
const database = admin.database(app)
module.exports = database
sessionSignout.js - Signout user after a specific time period - if specified. Default to eternal session.
const functions = require('firebase-functions')
const moment = require('moment')
const database = require('../../firebase-db')
const admin = database.app
//Import enviroment variable config (.env)
require('dotenv').config()
//Export cron job - deploy: firebase deploy --only functions:sessionSignout
exports.sessionSignout = functions
.region('europe-west1')
.pubsub
.schedule('*/15 * * * *')
.timeZone('Europe/Stockholm')
.onRun(async (event) => {
//Start execution
const now = moment()
const defaultSessionTime = 0 //Eternal session
//Get all users and calculate inactive time - time since last login
let logoutUsersArray = []
await database.ref(`users`)
.once('value', (usersSnapshots) => {
usersSnapshots.forEach((snapshot) => {
const userData = snapshot.val()
const lastLoginOut = (userData.lastLoginOut) ? userData.lastLoginOut : 0
//Only process users that has a login/out time stamp
if(lastLoginOut > 0){
const userSessionTime = (userData.sessExp) ? userData.sessExp : defaultSessionTime
const hoursSinceLastLoginOut = now.diff(lastLoginOut, 'hours')
const logoutUser = ( userSessionTime > 0 && (hoursSinceLastLoginOut > userSessionTime) )
if(logoutUser){
const userId = snapshot.key
const userName = (userData.alias) ? userData.alias : userData.displayName
const email = (userData.email) ? userData.email : ''
const userObject = {
userId,
userName,
email,
lastLoginOut,
diffHours: now.diff(lastLoginOut, 'hours')
}
logoutUsersArray.push(userObject)
}
}
})
})
console.log('logoutUsersArray', logoutUsersArray)
//Collect all promises to carry out
let myPromises = []
// Revoke all refresh tokens for each user
logoutUsersArray.forEach((logoutUser) => {
const uid = logoutUser.userId
myPromises.push(
admin.auth().revokeRefreshTokens(uid)
.then(() => {
return admin.auth().getUser(uid)
})
.then((userRecord) => {
return new Date(userRecord.tokensValidAfterTime).getTime() / 1000
})
.then((timestamp) => {
// Retrieve the timestamp of the revocation, in seconds since the epoch.
console.log('Tokens revoked at: ', timestamp)
return Promise.resolve(true)
})
.catch((err) => {
console.error('Error', err)
return Promise.reject(err)
})
)
})
//Execute promises
console.log('Execute promises')
return Promise.all(myPromises)
.then(() => Promise.resolve(true))
.catch((err) => {
console.error('Error', err)
return Promise.reject(err)
})
})//End sessionSignout
Documentation on firebase-admin can be found here.
Upvotes: 2
Reputation: 317467
The documentation you linked says that you can use the Firebase Admin SDK to revoke a user's refresh tokens in order to terminate their session. This code must run on a backend you control, which means that you won't be able to do it in the client app. The backend will need to know when the user became "inactive", by whatever definition of that you choose. Wiring this all up is non-trivial, but possible.
Upvotes: 5