Can't get a MapKitJS JWT token to work

I've used JWTs a lot for user authentication, but I can't get them to work with MapKitJS. I have a route that creates a token...


const privateKey = fs.readFileSync(__dirname + "/../MapKitJS_AuthKey.p8");
const token = jwt.sign({
  origin: event.local === true ? 'http://localhost:8080' : 'NO'
}, privateKey, {
  header: {
    kid: process.env.kid,
    typ: 'JWT',
    alg: 'ES256'
  },
  issuer: process.env.iss,
  expiresIn: '1h',
  algorithm: 'ES256'
});

I'm using node, and the resulting token looks just fine...

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkdBQUw3VlVWRzQifQ.eyJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwODAiLCJpYXQiOjE1NTE1MDkzNDgsImV4cCI6MTU1MTUxMjk0OCwiaXNzIjoiOEJVMlk4QzVKNyJ9.BSXts5IrsUyPfsPnkbI-MeUC3xpZkQ2K_1wsjMw-RrT3qLE7WSULFpmvF076V6HAU1J80vBCd5o8veRXCFWN4g

Looking at it in jwt.io it come out nicely...

{

"alg": "ES256",

"typ": "JWT",

"kid": "GAAL7VUVG4"

}

{

"origin": "http://localhost:8080",

"iat": 1551509348,

"exp": 1551512948,

"iss": "8BU2Y8C5J7"

}

But passing the toke to MapKitJS I always get "Bootstrap.init(): initialization failed because the authorization token is invalid." from the server. I'm at a loss. I have no idea what to do at this point.

Accepted Reply

Hi,


Well, your code and my code work. I needed to make a new certificate. I don't know why the one I was using is invalid. I've tried the old certificate with your code and it produces invalid tokens as well. The new certificate makes valid tokens is both versions of the code.


I would be interested in knowing if the old certificate I downloaded got corrupted somehow or if it was originally invalid, but I can't redownload it so there is no way to tell.


Anyway, thank you for your help, sorry I've been such a bother.


For anyone else reading this: The certificate was invalid. I made a new one Key and downloaded the new certificate and things worked.

Replies

No ideas? I can't really do anything until the token works. Whats the next level of support to try after silence from the community here?


To be honest I'm kind of surprised Apple doesn't have a generic token for the localhost origin.

Your token expiration is March 1st. Using Terminal:

$ date -r 1551512948
Fri Mar  1 23:49:08 PST 2019


Do new tokens have valid future expiration dates?


For future reference, if you don't get an answer on the forums, Developer Technical Support is available.

Hi, I posted this almost a week ago. It took days for the moderator to approve it. That’s said, if you looked at the code, the expiration is set properly. New tokens always have a future expropriation date.


It really seems like you didnt read my post at all. You just checked the token, without thinking, saw it was expired and "tada" thats it. After waiting days for the moderator to approve, and another day before a response, and then to have it be from an Apple employee who didn't even LOOK at the post :-/


Also, when I try to open a support ticket...

DTS does not provide support for pre-release software. To post questions and find answers related to pre-release software, visit the Apple Developer Forums.

An here comes another weekend for no support. Glad I paid $100 to try this. I’m sure it works great, if the stupid tokens worked properly. What a waste of time and money.

I did read your post. Token expiration is a common reason authentication fails, which is why I asked if new tokens have the expected expiration date - maybe you aren't always generating new ones for some reason, or maybe they are getting cached beyond the time limit, for instance. I tried your token code, except with replacing the origin claim with a straight localhost url. It worked successfully.


My token is passed to MapKit JS like this:

<script src="https://cdn.apple-mapkit.com/mk/5.x.x/mapkit.js"></script>
<script>
mapkit.init({
  authorizationCallback: function(done) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "/mapkitjs/jwt");
  xhr.addEventListener("load", function() {
  done(this.responseText);
  });
  xhr.send();
  }
});
</script>


So, this indicates the issue is one of the following:

  1. The token pased to MapKit JS is expired
  2. Your credentials aren't configured correctly
  3. You are passing the token to MapKit JS incorrectly - see example above
  4. There is an issue with the `event.local` statement that I'm not using
  5. There is something else wrong in your server enviroment.


The Developer Programs team can assist with number 2 if there's a configuration issue when you generated the Maps identifier and credentials.

DTS can help you with number 3, if you can provide a focused sample project of how your are initalizing MapKit JS

If the issue is with number 4 or 5, you will need to consult the help resources for your server enviroment.


MapKit JS is not in beta any longer - DTS does support it.

Hi jzaun, somehow I missed your post before today. Just wanted to let you know that duplicate claims will cause a token to be invalid.


(Cross-posting from https://forums.developer.apple.com/thread/113721)


Your token could be rejected because it contains duplicate claims. To check your token, execute this at the command line (substitute your token for your-token-here, but keep the quotes around it):


echo "your-token-here" | tr "." "\n" | head -2 | base64 -D


To check just the token header, use `head -1` in the above command.

Token I'm trying:

eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkdBQUw3VlVWRzQifQ.eyJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwODAiLCJpYXQiOjE1NTI0NDQ1NDcsImV4cCI6MTU1MjQ0ODE0NywiaXNzIjoiOEJVMlk4QzVKNyJ9._2H4qgImjfujDnyD_aapJW9sdFfwfb_iAi_8w7uM4APXuTJ6ucQTk_f3rYi53emdMX7CWsOLWIXr_EfcgRSrVQ


http://jwt.io gives me:


Header:

{
  "alg": "ES256",
  "typ": "JWT",
  "kid": "GAAL7VUVG4"
}


Payload:

{
  "origin": "http://localhost:8080",
  "iat": 1552444547,
  "exp": 1552448147,
  "iss": "8BU2Y8C5J7"
}


The commands you wanted me to try:

~/websites/test [master ↑·1|✚ 9…7] 
16:40 $ echo "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkdBQUw3VlVWRzQifQ.eyJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwODAiLCJpYXQiOjE1NTI0NDQ1NDcsImV4cCI6MTU1MjQ0ODE0NywiaXNzIjoiOEJVMlk4QzVKNyJ9._2H4qgImjfujDnyD_aapJW9sdFfwfb_iAi_8w7uM4APXuTJ6ucQTk_f3rYi53emdMX7CWsOLWIXr_EfcgRSrVQ" | tr "." "\n" | head -1 | base64 -D
{"alg":"ES256","typ":"JWT","kid":"GAAL7VUVG4" ~/websites/test [master ↑·1|✚ 9…7] 
16:42 $ echo "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkdBQUw3VlVWRzQifQ.eyJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwODAiLCJpYXQiOjE1NTI0NDQ1NDcsImV4cCI6MTU1MjQ0ODE0NywiaXNzIjoiOEJVMlk4QzVKNyJ9._2H4qgImjfujDnyD_aapJW9sdFfwfb_iAi_8w7uM4APXuTJ6ucQTk_f3rYi53emdMX7CWsOLWIXr_EfcgRSrVQ" | tr "." "\n" | head -2 | base64 -D
{"alg":"ES256","typ":"JWT","kid":"GAAL7VUVG4"}?&?&?v??#?&?GG?????6Ɔ?7C???"?&?B#?SS#CCCSCr?&W?#?SS#CC?Cr?&?72#?#?%S%??3T?r ~/websites/vue-extras [master ↑·1|✚ 9…7] 
16:42 $

My Init code:

mapkit.init({
  authorizationCallback: function (done) {
    fetch(`http://localhost:8081/token/mapkit`)
      .then((res) => res.text())
      .then((token) => {
        console.log(token);
        done(token);
      });
  },
  language: 'en',
});

My alternate Init code:

mapkit.init({
  authorizationCallback: function (done) {
    done('eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkdBQUw3VlVWRzQifQ.eyJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwODAiLCJpYXQiOjE1NTI0NDQ1NDcsImV4cCI6MTU1MjQ0ODE0NywiaXNzIjoiOEJVMlk4QzVKNyJ9._2H4qgImjfujDnyD_aapJW9sdFfwfb_iAi_8w7uM4APXuTJ6ucQTk_f3rYi53emdMX7CWsOLWIXr_EfcgRSrVQ');
  },
  language: 'en',
});


My route generates a new token every time:

case '/TOKEN/:TYPE':
  if (route.method === 'GET' && route.parms.type === 'mapkit') {
    if (!process.env.kid || !process.env.iss || !process.env.key) {
      done(500, `Missing key file environment variable(s)`);
      return;
    }

    const privateKey = new Buffer.from(process.env.key, 'base64')
    // const privateKey = fs.readFileSync(__dirname + "/../MapKitJS_AuthKey.p8");

    jwt.sign({
      origin: event.local === true ? 'http://localhost:8080' : 'NO'
    }, privateKey, {
      keyid: process.env.kid,
      issuer: process.env.iss,
      expiresIn: '1h',
      algorithm: 'ES256',
    }, (err, token) => {
      if (err) {
        done(500, err);
      } else {
        done(200, token);
      }
    });
  } else {
    done(405, `Method Not Allowed: ${route.method}`);
  }
  break; 
  1. The token isn't expired. The one I am trying here expires an hour from now
  2. I have no idea how to check if my credentials are correct. I followd the directions here: https://developer.apple.com/documentation/mapkitjs/setting_up_mapkit_js
  3. As far as I can tell I'm passing the token to the MapKitJS correctly. I see the console log from my code, I see the error from MapKitJS.
  4. In the server code, event.local is hard coded to true. As you can see in the token itself, the origin is 'http://localhost:8080', not NO. I am accessing a local http server with 'http://localhost:8080'as the URL and when looking at the chrome network tab for the init call I can in fact see the server is sending the Origin header set to http://localhost:8080. The token route is on http://localhost:8081, a differnet server.
  5. This isn't an issue with my server in general. If I change my init code to just return the token as a string I get the same response, you can see my alternate init code above.


The node package I'm using to generate the token is 'jsonwebtoken' version '^8.5.0'.


I really have no idea what to try. The error the server gives is generic and not helpfull.

I've looped in a few other people on my side to look into this, and will update this thread once more info is available.

Another week goes by. Has *anyone* on here gotten MapKitJS to work? If so, how are you making your token? Can you post an expired token so I can compare with mine? I’m tempted to just give up and use google.

Can you update your init call to mine posted previously? Similarly, if you take the content of one of the examples we have available, and change only the server address to your localhost:8081 server for the token, what is the result?

Somewhere, your code is sending tokens with single quote marks, which aren't a valid part of the JWT payload. My suggestion to try those examples are to eliminate if it's your init code or server. Additionally, can you try with passing a token generated from the same port and see if that makes a difference? What's in the Safari console log?

My token is valid as far as I can tell... every time I check it, it looks fine. You can't have single quotes inside a token, besides jwt.io says its double.


I tried your init code above with the XMLHttpRequest and I get the same result.


I'm trying a token, with *no* origin and a 1 week expire date.


This *should* work for anyone for the next week...


eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IkdBQUw3VlVWRzQifQ.eyJpYXQiOjE1NTMzMTE4MTcsImV4cCI6MTU1MzkxNjYxNywiaXNzIjoiOEJVMlk4QzVKNyJ9.vHmoj_MODPsQTsxinsQMRDI2icSl0E7a5g3uEIApuIT6RnVgIFGpKN1_eeOuIzRyNWWhusO1nYsFPpo3hRzUbQ

Error from Safari:


[Error] Failed to load resource: the server responded with a status of 401 (Unauthorized) (bootstrap, line 0)
[Error] Failed to load resource: the server responded with a status of 401 (Unauthorized) (bootstrap, line 0)
[Error] Failed to load resource: the server responded with a status of 401 (Unauthorized) (bootstrap, line 0)
[Error] Bootstrap.init(): initialization failed because the authorization token is invalid.



Here is the demo code with my 1 week token. It fails for me. does it for you?


https://github.com/zaun/mapkitjs-test/blob/master/test.html

Why is does my reply have to be moderated. 😟 just more time wasted. I opend a TSI ticket 711029050. Its dumb, they ask for a app name and app ID, I dont have one, its web based.

Haven’t received anything on the support ticket beyond the initial auto-reply. Nothing new here. Not sure what else to do. I’m **** and no support even with the paid ticket. :(

Your support ticket was responded to on Monday. I will have it resent, please check it didn't get captured by a filter in your email.