Problem With Auth0 Custom Authorizer in Examples Repo (CORS / 401 Unauthorized)

EDIT: I posted a link to my implementation, possibly triggering the forum immune system to mark this post as spam. Removing the link to my implementation. Screenshots showing the issue are in the following posts.


If someone wouldn’t mind pointing out the (probably obvious) flaw in my deploy I would greatly appreciate it…

Here [link redacted] we have my attempt to deploy an exact clone of the Auth0 Custom Authorizer Function Example. Public endpoint works. Login works. The private endpoint resulting in a CORS error in the browser. (Test with login: test@test.com / fdsa)

You can find a working example with all endpoints working by following the Auth0 Custom Authorizer github repo link above.

The CORS setting in serverless.yml on each endpoint are, a bit different.

  publicEndpoint:
    handler: handler.publicEndpoint
    events:
      - http:
          path: api/public
          method: get
          integration: lambda
          cors: true
  privateEndpoint:
    handler: handler.privateEndpoint
    events:
      - http:
          path: api/private
          method: get
          integration: lambda
          authorizer: auth # See custom authorizer docs here: http://bit.ly/2gXw9pO
          cors:
            origins:
              - '*'
            headers:
              - Content-Type
              - X-Amz-Date
              - Authorization
              - X-Api-Key
              - X-Amz-Security-Token

Being fairly new to CORS and Serverless I can’t seem to find the flaw, even after digging through the request / response headers. I’m hoping someone can point me in the right direction. Any tips?

hi @rsweetland,

can you post the exact CORS error? a screenshot of the browser debugger window will do. Need to know which endpoint you are trying to reach, whether it’s the GET or OPTIONS that’s failing etc.

Also, your complete yaml file would be good too - where are you defining the auth function?

cheers,
Chris.

OK I think the CORS is misleading, as this is not set on your 401 response. So let’s focus on the real problem: your 401 error.

401 means that your request is unauthorised… so your auth0 authoriser is failing.

did you replace the code here in the example authoriser?

const AUTH0_CLIENT_ID = 'your-auth0-client-id-here';
const AUTH0_CLIENT_SECRET = 'your-auth0-client-secret-here';

?

Ah! It is the auth function. Awesome. Thank you.

I did enter (and just double-checked) those values.

I added some logs around the auth function and found an invalid signature error. However, when I paste the token into jwt.io with the AUTH0_CLIENT_SECRET value the signature says it’s valid.

(Forum not letting me post a link to the github code for some reason. Authorizer function pasted below)

    const token = event.authorizationToken.substring(7); //i'm logging to token to verify on jwt.io
    const options = {
      audience: AUTH0_CLIENT_ID,
    };
    jwt.verify(token, new Buffer(AUTH0_CLIENT_SECRET, 'base64'), options, (err, decoded) => {
      if (err) {
        cb('Unauthorized'); // <---- invalid signature error being thrown here
      } else {
        cb(null, generatePolicy(decoded.sub, 'Allow', event.methodArn));
      }
    });

The fact the that the live demo is working fine gives me hope that it’s me, not the code.

Any ideas? Thanks again.

hi @rsweetland

from our experience, we could not get the jwt.verify function to work!! The signature just would not validate, just like what you are experiencing.

Instead, we post to Auth0, and we let them tell us whether it’s a valid token or not

Like this:

var https = require('https');


console.log('Loading function');

exports.handler = function (event, context) {
  console.log('Client token: ' + event.authorizationToken);
  console.log('Method ARN: ' + event.methodArn);

  var token = event.authorizationToken;

  var options = {
    host: '<your account>.auth0.com',
    path: '/tokeninfo',
    method: 'POST',
    port: '443',
    headers: { 'Content-Type': 'application/json' }
  };

  var req = https.request(options, function (response) {
    var data = ''
    response.on('data', function (chunk) {
      data += chunk;
    });

    response.on('end', function () {
      if (data == 'Unauthorized') {
        return context.fail('Unauthorized'); // HTTP status 401
      }

      var principalId = 'user';
      var apiOptions = {};
      var tmp = event.methodArn.split(':');
      var apiGatewayArnTmp = tmp[5].split('/');
      var awsAccountId = tmp[4];
      apiOptions.region = tmp[3];
      apiOptions.restApiId = apiGatewayArnTmp[0];
      apiOptions.stage = apiGatewayArnTmp[1];

      var policy = new AuthPolicy(principalId, awsAccountId, apiOptions); // this builds your policy
      policy.allowAllMethods();

      context.succeed(policy.build());
    });

  });

  req.write(JSON.stringify({ 'id_token': token }));
  req.end();
};

We tried a lot to get jwt.verify to work, but in the end our best bet was to ask Auth0. We might revisit in the future, but for now it’s good for us.

For AuthPolicy (which I omitted) you can use something like this: https://github.com/amowu/aws-auth-policy

hope this helps :slight_smile:

2 Likes

Huge help. This led me right to the issue.

Just two days ago a PR was submitted on the examples repo to fix the bug. More info on issue #62 in the Serverless Examples Repo (forum is not letting me post a link!)

PR not yet merged, but in the meantime I manually removed the base64 encoding of the AUTH0_CLIENT_SECRET and it worked.

Working auth function (without base64 encoding):

    jwt.verify(token,  AUTH0_CLIENT_SECRET, options, (err, decoded) => { //removed Buffer
      if (err) {
        cb('Unauthorized');
      } else {
        cb(null, generatePolicy(decoded.sub, 'Allow', event.methodArn));
      }
    });

Thanks again @str3tch Really appreciate your help!