Skip to content

Instantly share code, notes, and snippets.

@thameera
Last active February 3, 2024 00:42
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thameera/2dfb3dff6ed2ec461aef7a7a2e3d3250 to your computer and use it in GitHub Desktop.
Save thameera/2dfb3dff6ed2ec461aef7a7a2e3d3250 to your computer and use it in GitHub Desktop.
Actions redirect example
/**
* 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}`)
})
@fullstackfool
Copy link

Saved me from hours of going in circles. Cheers mate!

@GrapeJuice787
Copy link

Thank you for this one, been fighting with this for a day now 😆

@rrab-0
Copy link

rrab-0 commented Feb 2, 2024

Do you generate token again from backend just in case the one from "Post Login" expires? @thameera

@thameera
Copy link
Author

thameera commented Feb 3, 2024

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment