Connecting a legacy system during Auth0 login

I am sure this is easy to everyone else. But I have searched for weeks and only get close to a solution, but nothing that completes the suggested implementation. I am hoping to use a Post Login Action and redirect to an OWIN Web API that connects to the legacy system and produces a code that system can understand. I want the trigger to report an error if the code cannot be generated which means that the user profile is not mapped in the legacy system.

This is the code I have in the Post Login trigger code:
exports.onExecutePostLogin = async (event, api) => {
// If the user has already been assigned a TempLoginCode
// if( event.user.app_metadata.TempLoginCode ) {
// return;
// }
// api.user.setAppMetadata(“TempLoginCode”, “HaveValue”);
const token = api.redirect.encodeToken({
secret: event.secrets.MY_SHARED_SECRET,
payload: {
email: event.user.email,
},
});

api.redirect.sendUserTo( “http://l/account/enrichment”, {
query: { session_data: token }
});
};

exports.onContinuePostLogin = async (event, api) => {
//api.user.setUserMetadata(“FixTempCode”, “Fix2Value”);
//api.user.setAppMetadata(“FixAppCode”, “FixAppValue”);
try {
const payload = api.redirect.validateToken( {
secret: event.secrets.MY_SHARED_SECRET,
tokenParameterName: ‘session_token’,
});
// api.user.setAppMetadata(“claimCode”,
// payload.session_token.Subject.claims[“clmCode”]);
// api.user.setAppMetadata(“NewTempCode”, payload.claims[“NewTempCode”]);
// api.user.setAppMetadata(“FixSecondCode”, event.request.query.newtempcode);
} catch(e) {
console.log(“Error:”, e);
}
};

After days of searching, I found some sample web api MVP Code in which I am able to catch the call from Auth0. Written using .net version 4.6, this code is:
public ActionResult Enrichment( string state, string session_data )
{
try
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = “MYDOMAIN.us.auth0.com”,
ValidateAudience = false,
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey( Encoding.UTF8.GetBytes( MySecretValue ) ),
ClockSkew = TimeSpan.Zero
};

			var handler = new JwtSecurityTokenHandler();
			var jsonToken = handler.ReadToken( session_data ) as JwtSecurityToken;

			if( jsonToken == null )
				throw new SecurityTokenException( "Invalid JWT token" );

			//string emAddr = jsonToken.Claims.Where( emClaim => emClaim.Type == "email" ).First().Value;

//This area will be enhanced to communicate with the legacy system and
// produce a code to be returned

			var tokenDescriptor = new SecurityTokenDescriptor
			{
				Issuer = jsonToken.Issuer,
				Expires = jsonToken.ValidTo,
				SigningCredentials = new SigningCredentials( new SymmetricSecurityKey(
					Encoding.UTF8.GetBytes( MySecretValue ) ),
					SecurityAlgorithms.HmacSha256 ),
				Subject = new ClaimsIdentity( new[]
				{
					new Claim("state", state),
					new Claim("sub", jsonToken.Subject),
					new Claim("clmCode","ANewValue")
				} )
			};

			var token = handler.CreateToken( tokenDescriptor );

			return View( "Redirect", new RedirectViewModel
			{
				State = state,
				SessionToken = handler.WriteToken( token ),
				NewTempCode = "SimpleTest"
			} );
		}
		catch( Exception ex )
		{
			// Handle exception
			// Console.WriteLine( ex );
			throw new Exception( "Token could not be decoded", ex );
		}
	}

the view code
@using global::SampleTwo.Models
@model RedirectViewModel

Loading...

;

You can see my commented code in the trigger code for onContinuePostLogin. You can also see that I have tried passing information in the claim collection, on the query string, and in the payload.

So - I face the following failures:

  1. How do I properly send the code back to the trigger? Claim? Query? Payload? Other?
  2. What do I do in the trigger so that my Angular front-end can see it for the calls that already work with a direct login connection against the legacy system? (Note - in my angular, I can use the User object - but not UserMetadata, AppMetadata, nor claims.
  3. I can’t even see how to find the console log used in the /continue effort as it might have additional clues fo rme.

Obviously, I am new to most of this, but have searched a long time. I can’t even find, a second time, the code for my web api so I am happy this part connects to Auth0 currently. Many blurbs refer to .net core which I cannot use yet. Almost every example I find simply assumes that these pieces are so easy that there needs to be no example. Unfortunately, that is not true for me and I simply cannot progress.

I would be most grateful for links to complete code samples or directions I can follow to make this work.

I just ran into a post that makes me question my approach. I had assumed that the api.access.deny call would prevent a successful login - but it appears to only refuse to create the token. What I actually want is a trigger that fires after they have been authenticated, but to give me the ability to prevent the login completion if the mapping to the legacy system hasn’t been created. Is that possible? I don’t really want to auto-logout if confirmation with the legacy system fails since they might have logged into to Auth0 before launching my app and been active elsewhere.

Hi Lance,

api.access.deny does deny the login, so they will be recycled right back to the sign-on page.

I have a lot of questions about exactly what you are trying to do. But, maybe a better solution would be a simple as using a database connection with the legacy system as a remote database? The connection is handled through actions, so you can write the code to talk to any source. You have the option of always using the legacy system, or a lazy migration (JIT) of the user information into Auth0 so the next time the user signs on we don’t bother checking again.

I am confused about the Angular comments. You should be able to see the ID token and all it’s claims in Angular. With or without JIT the solution is to write the “GetUser” script for the databse connection to retrieve any data you want from the legacy system, and put it into user_metadata. Then in a post-login action stuff that data into the ID token claims for Angular.

One change from the initial post. My test application in the back end was OWIN. However, my ideal condition will be a simple .net web api that is not OWIN. I am able to receive the redirect from the post-login trigger and respond to it. But again, I don’t see any claims or metadata. Is there a special permission I need to enable to make that available?

If you look at my code above, I have tried a number of things to set a value somewhere. However - when I execute the getUser call in the Angular code, I cannot see the UserMetadata - nor can I see the AppMetaData. The claim value I added above of “clmCode” is not there. Nor can I see evidence of “NewTempCode” which I tried to pass.

I cannot merely use my system in the background because we have some contracts where the customer wants us to permit the Auth0 login from a certain client to create an account if it didn’t already exist.
So yes - your answer repeats what is suggested in many areas. My problem is that nothing I have tried actually achieves the promised results. I am surely missing something simple. I just can’t figure out what that last element might be.

Hi Lance! Sorry my schedule is a little off, I’m delivering the Auth0 CIC class to a group in India, I will finish in the morning EDT.

#1, I only addressed stuffing something into the ID token in general terms. My bad, I should have included an example because I do not see you doing that. It would look like this example I pulled from one of my personal examples; https://github.com/jmussman/auth0-publish-scopes/:

await api.idToken.setCustomClaim('x-permissions', permissions);

#2, I am still having trouble following what you are trying to accomplish. Especially the part about redirecting to an API. Normally we would just call an API directly; an application would redirect to an authorization server to have the user authenticated. I think I’m missing a big chunk here :slight_smile: This is kind of throwing me too, because it sounds like you want to provision a user in an app that is accepting your Auth0 tenant as the source of identity. In certain cases: “…we have some contracts where the customer wants us to permit the Auth0 login from a certain client to create an account if it didn’t already exist.”

I think we need to understand the architecture and the goals better:

  1. Are the application looking for authentication and the API related?
  2. Maybe the application is driving the API, and you need to deny access or provision the user in the API depending on circumstances?
  3. Or is this simply an adjacent API that we are checking for the user? Can we make a simple API call to check?
    4.The code seems to be simply an attempt to define if the user is provisioned, but where is it supposed to go, and the error supposed to be handled?
  4. Are what we are really trying to do is to
    a. Check that the user exists
    b. Check the source
    c. Deny the user if the source doesn’t expect provisioning
    d. Create the user at the API if they do, and then let the user proceed?

If you can explain the architecture better, and what the goal is… I mean what is there right now and what needs to be accomplished, not the solution above. Then maybe I can help you fix the solution or propose something better.

Thanks for taking a moment to look at this. My problem is that I am not in the trigger code so the reference to “api.idToken.setCustomClaim” feels like it might be in the onContinue routine that happens later. I am in the .net web where I am trying to return a value (or enhance the token) through the Auth0 interchange so that the onContinue routine can read it to determine whether to deny… and if not deny, use the enhanced information to deliver that additional property to the Angular code that tried to login.