0

I want to write e2e tests that can run in our CI environment which is tightly locked down and has no internet access.

I am using the auth0 react loginWithRedirect function which will attempt to redirect to the auth0 login on their servers and will timeout on CI.

I am able to intercept the call to /authorize in express:

app.get('/auth0/:simulation_id/authorize', middleware, (req, res) => {
  const { client_id, redirect_uri, scope, state } = req.query;

Is it now possible for me to generate a mock oauth token that will be accepted by the @auth0/react client code?

dagda1
  • 26,856
  • 59
  • 237
  • 450
  • Could you mock the client-side too? Would likely make this a lot easier. – Evert Feb 27 '21 at 23:38
  • @Everet how would you mock the hook? some sort of hoisting override? – dagda1 Feb 28 '21 at 07:51
  • The normal suggestion to making anything mockable is to inject it. e.g.: provide it as an argument. Mocking frameworks might be able to do more magical things, but if all that fails.. just fall back on simple method arguments. – Evert Feb 28 '21 at 07:53

2 Answers2

1

Yes. Using the jsrsasign.js library, where accessKey contains a private key:

function createJwt(username, type, realm, scopes, sessionId, expires_in, audience) {

    var oHeader = {
        alg: 'RS256',
        typ: 'JWT'
    };
    // Payload
    var oPayload = {};
    var tNow = jwt.KJUR.jws.IntDate.get('now');
    var token_expiry = expires_in;
    var tEnd = tNow + token_expiry;

    oPayload.sub = username;
    oPayload.auditTrackingId = uuidv4();
    oPayload.iss = "https://mock.org/identities/v1/" + realm + "/token";
    oPayload.tokenName = type;
    oPayload.token_type = 'Bearer';
    oPayload.authGrantId = !sessionId ? uuidv4() : sessionId;
    oPayload.aud = (audience ? audience : "https://mock.org/identities/v1/" + realm + "/token");

    oPayload.nbf = tNow;
    oPayload.scope = scopes;
    // oPayload.auth_time = tNow;
    oPayload.realm = '/' + realm;

    oPayload.exp = tEnd;
    oPayload.expires_in = token_expiry * 100000;
    oPayload.iat = tNow;

    oPayload.jti = uuidv4();

    var sHeader = JSON.stringify(oHeader);
    var sPayload = JSON.stringify(oPayload);

    var prvKey = accessKey;

    var sJWT = jwt.KJUR.jws.JWS.sign("RS256", sHeader, sPayload, prvKey);


    return sJWT;
}

Set the audience, subject, scp and any other properties in line with the tokens that auth0 is creating.

You also might need to mock out the jwk endpoints, but I doubt the library will care. If it doesn't work it will be due to certain properties not being available on the token.

You might need to create an id token as well, depending on your setup.

Access key is similar to this:

var accessKey = jwt.KEYUTIL.getKey("-----BEGIN PRIVATE KEY-----\n" +
    "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC0g+nePEZ6aFiH\n" +
    "ccnle/ryqz1lNvloPGuA5b6GeE8MrT7SATxv54zQ2LnvuRp86cd32elL0YAw3GMc\n" +

... snip ...

    "Rno3R82z6SAvy9HgIMzfti5NSVgqC9nmhFEs+ChFWuboGotVV99COVJId9S/567n\n" +
    "kz90cLENtD/8JTYAhLea5F/PJBJJHSvQT298ZxR4bw1vQ5Bq2FMnLSYuIOQMkQdr\n" +
    "Yqt+8gXW0+3kfyb3cCyI+2HKcQ==\n" +
    "-----END PRIVATE KEY-----\n");

And keep going til you've mocked out the entire IdP platform :) (I basically did the same thing with OpenAM a few years ago).

stringy05
  • 6,511
  • 32
  • 38
-1

In addition to @stringy05's response; if you've got back-end services (e.g. Java, .NET, etc) that are called by your React app and need to do JWT validation, you might need to statically host your own an OpenID Configuration and JSON Web Key Set endpoints in your own environment.

The reason for this is because JWT validation (by back-end services) would still require communication to the external authorization server. With JWT-based auth this is generally limited to a single (up-front or lazy-loaded) request to get the public key for signature validation, but there could also be additional calls e.g. when the service encounters an unknown kid (key ID) on a JWT, as well as a periodical refresh interval (e.g. daily).

For Auth0 OpenID Configuration and JSON Web Key Set endpoints are hosted at the following locations:

  • OpenID Configuration: https://[tenant-name].[2-letter-iso-country-code].auth0.com/.well-known/openid-configuration
  • JSON Web Key Set: https://[tenant-name].[2-letter-iso-country-code].auth0.com/.well-known/jwks.json

These are just static JSON documents. You can probably just copy these from one of your existing tenants, modify accordingly, and then host in your own environment. The modifications you'd need to make include:

  • OpenID Configuration to reference local jwks_uri endpoint.
  • Update the key information in the JSON Web Key Set endpoint. Note: you can generate an asymetric key pair using OpenSSL, and see here for information about how to extract modulus and exponent from public key (which are required for the JWKS document). Note: in your React app, you'd need to sign the tokens with the private key that you generate.

Once you've done the above, your back-end services can reference the locally hosted OpenID Configuration and will be able to do JWT validation without communicating to an external authorization server.

Ryan.Bartsch
  • 3,698
  • 1
  • 26
  • 52