-
-
Save thameera/2dfb3dff6ed2ec461aef7a7a2e3d3250 to your computer and use it in GitHub Desktop.
/** | |
* Handler that will be called during the execution of a PostLogin flow. | |
* | |
* @param {Event} event - Details about the user and the context in which they are logging in. | |
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login. | |
*/ | |
exports.onExecutePostLogin = async (event, api) => { | |
// Craft a signed session token | |
const token = api.redirect.encodeToken({ | |
secret: 'keyboardcat', // IMPORTANT: Read this from event.secrets | |
expiresInSeconds: 60, | |
payload: { | |
// Custom claims to be added to the token | |
email: event.user.email, | |
externalUserId: 1234, | |
}, | |
}); | |
// Send the user to http://localhost:3000/redirect along | |
// with a `session_token` query string param including | |
// the email. | |
api.redirect.sendUserTo("http://localhost:3000/redirect", { | |
query: { session_token: token } | |
}); | |
}; | |
/** | |
* Handler that will be invoked when this action is resuming after an external redirect. If your | |
* onExecutePostLogin function does not perform a redirect, this function can be safely ignored. | |
* | |
* @param {Event} event - Details about the user and the context in which they are logging in. | |
* @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login. | |
*/ | |
exports.onContinuePostLogin = async (event, api) => { | |
const payload = api.redirect.validateToken({ | |
secret: 'keyboardcat', // IMPORTANT: Read this from event.secrets | |
tokenParameterName: 'my_token', | |
}); | |
console.log(payload); | |
}; |
/* | |
* IMPORTANT: | |
* This code is meant for demo purposes only, and is not production-ready. | |
* More info: https://auth0.com/docs/actions/triggers/post-login/redirect-with-actions | |
*/ | |
const express = require('express') | |
const jwt = require('jsonwebtoken') | |
const PORT = process.env.PORT || 3000 | |
const SECRET = 'keyboardcat' // For demo purposes only. Should not be committed in source file. | |
const TENANT_DOMAIN = 'tham.auth0.com' | |
const app = express() | |
/* | |
* Validate the incoming token from Auth0 | |
* This can be generated in the Action by the api.redirect.encodeToken() method | |
*/ | |
const validateIncomingToken = (req) => { | |
if (!req.query || !req.query.session_token) { | |
throw 'No session_token found' | |
} | |
try { | |
const decoded = jwt.verify(req.query.session_token, SECRET) | |
return decoded | |
} catch (e) { | |
throw 'Invalid session_token' | |
} | |
} | |
/* | |
* Generate new session token to be sent to Auth0 | |
*/ | |
const generateNewToken = (data, state) => { | |
const payload = { | |
sub: data.sub, // Mandatory, must match incoming token's sub | |
iss: 'my-redirect-app', // Optional, not validated | |
state, // Mandatory, validated by Auth0 | |
color: 'blue', // Optional custom parameters to be used in Actions | |
} | |
// Even though iat and exp are not added above, they are implicitly added by the jwt library | |
const token = jwt.sign(payload, SECRET, { expiresIn: '60s' }) | |
return token | |
} | |
app.get('/redirect', (req, res) => { | |
try { | |
const incomingData = validateIncomingToken(req) | |
const newToken = generateNewToken(incomingData, req.query.state) | |
const url = `https://${TENANT_DOMAIN}/continue?state=${req.query.state}&my_token=${newToken}` | |
res.redirect(url) | |
} catch (e) { | |
res.send(e) | |
} | |
}) | |
app.listen(PORT, () => { | |
console.log(`App listening at http://localhost:${PORT}`) | |
}) |
Thank you for this one, been fighting with this for a day now 😆
Do you generate token again from backend just in case the one from "Post Login" expires? @thameera
Do you generate token again from backend just in case the one from "Post Login" expires? @thameera
The token coming from the Action can/should be consumed immediately and verified. Even if the user stays a long time on the redirected page, you would generally not need to validate that token again. Also note that the token we send back to Auth0 is a new one and different from the one we received from Auth0.
So ideally there shouldn't be a situation where the token fails to validates due to expiry (unless some user is trying to replay a request, in which case it should rightly be denied).
Saved me from hours of going in circles. Cheers mate!