Problem statement
How can data be passed back to Auth0 when implementing a Redirect with Actions? The documentation on Pass information back to the Action includes the following:
A signed session token should be used to send sensitive information back to Auth0.
The token will be validated to ensure that:
- The signature is valid.
- The token is not expired.
- The state claim within the token matches the state parameter used as part of the redirect.
To avoid replay attacks, the token should be sent back to Auth0 by making a POST request to the
/continue
endpoint. ThetokenParameterName
option in the code allows you to specify the name of the field that contains your token.
Is there an example of how to implement this on the application side?
Steps to reproduce
Create a post-login Action in your Auth0 tenant. You can use the following code as a guide:
exports.onExecutePostLogin = async (event, api) => {
// Craft a signed session token
const session_token = api.redirect.encodeToken({
secret: "RANDOM-256-BITS-SECRET",
expiresInSeconds: 500,
payload: {
sub: event.user.user_id,
continue_uri: `https://YOUR-AUTH0-DOMAIN/continue`
},
});
// Send the user to your application along
// with a `session_token` query string param including
// the email.
console.log("Redirecting outside of Actions");
// For the Action to work with the ASP.NET Core MVC app, you need to change the redirection to "http://localhost:3000/Auth/Redirect" instead
api.redirect.sendUserTo("http://localhost:3000/redirect"", {
query: { session_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) => {
console.log("validating token" );
try{
const payload = api.redirect.validateToken({
secret: "RANDOM-256-BITS-SECRET",
tokenParameterName: 'session_token'
});
console.log("payload", payload);
}catch(e){
console.log("error --->", e);
}
};
Solution
The following is an example of how to implement this within an application.
Regular Web App
Parting from the ASP.NET Core MVC quickstart, the following changes were made to get the Action redirection working in a test app:
- Create a Controller: Create a controller, for example,
AuthController
, and add an action namedRedirect
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using SampleMvcApp.ViewModels;
using System.Security.Claims;
namespace SampleMvcApp.Controllers
{
public class AuthController : Controller
{
private readonly IConfiguration _configuration;
public AuthController(IConfiguration configuration)
{
_configuration = configuration;
}
public IActionResult Redirect(string state, string session_token)
{
try
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = _configuration["Jwt:Issuer"],
ValidateAudience = false,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"])),
ClockSkew = TimeSpan.Zero
};
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(session_token) as JwtSecurityToken;
if (jsonToken == null)
{
throw new SecurityTokenException("Invalid JWT token");
}
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = jsonToken.Issuer,
Expires = jsonToken.ValidTo,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecretKey"])), SecurityAlgorithms.HmacSha256),
Subject = new ClaimsIdentity(new[]
{
new Claim("state", state),
new Claim("sub", jsonToken.Subject)
})
};
var token = handler.CreateToken(tokenDescriptor);
return View("Redirect", new RedirectViewModel
{
State = state,
SessionToken = handler.WriteToken(token)
});
}
catch (Exception ex)
{
// Handle exception
Console.WriteLine(ex);
throw new Exception("Token could not be decoded", ex);
}
}
}
}
- Create a ViewModel: Create a ViewModel class to hold the data to be passed to the view.
using System;
namespace SampleMvcApp.ViewModels
{
public class RedirectViewModel
{
public string State { get; set; }
public string SessionToken { get; set; }
}
}
- Create a View: Create a view file named Redirect.cshtml in the Views/Auth folder (or any other folder you prefer).
@using SampleMvcApp.ViewModels
@model RedirectViewModel
<h1>Loading...</h1>
<form id="redirectForm" method="post" action="https://YOUR-AUTH0-DOMAIN/continue?state=@Model.State">;
<input type="hidden" name="state" value="@Model.State" />
<input type="hidden" name="session_token" value="@Model.SessionToken" />
</form>
<script>document.getElementById('redirectForm').submit();</script>
- Configure JWT Settings in
appsettings.json
: Ensure you have the JWT settings configured in yourappsettings.json
file.
{
...
"Jwt": {
"Issuer": "YOUR-AUTH0-DOMAIN",
"SecretKey": "RANDOM-256-BITS-SECRET"
}
}
That should be enough to get the Action Redirect working.