Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jatinvaidya/33a07757c6a8b1651fbf41c408f6c8ea to your computer and use it in GitHub Desktop.
Save jatinvaidya/33a07757c6a8b1651fbf41c408f6c8ea to your computer and use it in GitHub Desktop.
Client Specific Session Lifetime POC
/* * * *
* This is just a library of utility functions
* There is NO STATE maintained in `global`
* NOT PRODUCTION READY !!
* * * */
function functionsLibrary(user, context, callback) {
const uuid = require("[email protected]");
const isInteractiveAuthentication = () => {
const leeway = 5; // seconds
if (context.authentication && context.authentication.methods) {
//Check if authn method match pwd or social connections
const authMethod = context.authentication.methods.find((method) => {
return method.name === "pwd" || method.name === "federated";
});
if (!!authMethod) {
let authnTimeStamp = authMethod.timestamp;
let currentDate = new Date();
let currentEpochTimeStamp = currentDate.getTime();
let currentAbsoluteSessionAge = Math.trunc(
(currentEpochTimeStamp - authnTimeStamp) / 1000
);
return currentAbsoluteSessionAge <= leeway;
} else {
console.info(`invalid auth method`);
return false;
}
}
};
const getInteractiveAuthenticationTimestamp = () => {
if (context.authentication && context.authentication.methods) {
//Check if authn method match pwd or social connections
const authMethod = context.authentication.methods.find((method) => {
return method.name === "pwd" || method.name === "federated";
});
if (!!authMethod) return authMethod.timestamp;
}
return null;
};
const isSilentAuthentication = () => {
return isInteractiveAuthentication() ? false
: context.protocol === "oidc-basic-profile" ? true : false;
};
const isRefreshTokenGrant = () => {
return context.protocol === "oauth2-refresh-token";
};
const isAbsoluteSessionTimeout = () => {
return (
(getCurrentTimestamp() - getInteractiveAuthenticationTimestamp())/1000 >=
context.clientMetadata.absolute_session_lifetime
);
};
const isInactivitySessionTimeout = (lastActivityTimestamp) => {
return (
(getCurrentTimestamp() - lastActivityTimestamp)/1000 >=
context.clientMetadata.inactivity_session_lifetime
);
};
const getCurrentTimestamp = () => new Date().getTime();
const getRedisClient = () => {
let redisClient = global.redisClient;
if (!redisClient) {
const redis = require("[email protected]");
redisClient = redis.createClient({
host: "removed",
port: "35984",
});
redisClient.auth("removed");
redisClient.on("error", function (err) {
throw err;
});
global.redisClient = redisClient;
}
return global.redisClient;
};
const getLastActivityTimestamp = async () => {
const sessionId = getSessionId();
console.info(`[getLastActivityTimestamp] sessionId: ${sessionId}`);
if (!!sessionId) {
const cacheKey = `${user.user_id}:${context.clientID}:${sessionId}:last_activity`;
console.info(`[getLastActivityTimestamp] cacheKey: ${cacheKey}`);
const lastActivityTimestamp = await getRedisString(cacheKey);
console.info(
`[getLastActivityTimestamp] lastActivityTimestamp: ${lastActivityTimestamp}`
);
return lastActivityTimestamp;
}
return null;
};
const setLastActivityTimestamp = async (lastActivityTimestamp) => {
const sessionId = getSessionId();
if (!!sessionId) {
const cacheKey = `${user.user_id}:${context.clientID}:${sessionId}:last_activity`;
console.info(`[setLastActivityTimestamp] cacheKey: ${cacheKey}`);
await setRedisString(cacheKey, lastActivityTimestamp);
//TBD TTL: context.clientMetadata.absolute_session_lifetime
}
};
const getSessionId = () => {
if (isRefreshTokenGrant()) return context.request.body.x_session_id;
else if (isSilentAuthentication())
return context.request.query.x_session_id;
else if (isInteractiveAuthentication()) return user.x_session_id;
};
const generateSessionId = () => {
user.x_session_id = uuid.v4();
};
const getRedisString = (key) => {
return new Promise((resolve, reject) => {
getRedisClient().get(key, (error, response) => {
if (error) reject(error);
else resolve(response);
});
});
};
const setRedisString = (key, value) => {
return new Promise((resolve, reject) => {
getRedisClient().set(key, value, (error, response) => {
if (error) reject(error);
else resolve(response);
});
});
};
global.isInteractiveAuthentication = isInteractiveAuthentication;
global.isSilentAuthentication = isSilentAuthentication;
global.isRefreshTokenGrant = isRefreshTokenGrant;
global.getInteractiveAuthenticationTimestamp =
getInteractiveAuthenticationTimestamp;
global.isAbsoluteSessionTimeout = isAbsoluteSessionTimeout;
global.isInactivitySessionTimeout = isInactivitySessionTimeout;
global.getCurrentTimestamp = getCurrentTimestamp;
global.getRedisClient = getRedisClient;
global.getLastActivityTimestamp = getLastActivityTimestamp;
global.setLastActivityTimestamp = setLastActivityTimestamp;
global.getSessionId = getSessionId;
global.generateSessionId = generateSessionId;
return callback(null, user, context);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment