JWT in Crossmark

JWT in Crossmark



Crossmark serves up a widget script to be embedded in publisher websites. The widget script is a small JavaScript file that extracts the DOI from the webpage and shows a dialog with the correct

In the past, some publishers have copied-and-pasted, reimplemented, reverse-engineered and re-created the widget. This has led to the product behaving in unexpected ways, for example:

  • using the wrong hostname
  • using the wrong version of the dialog server
  • using HTTPS vs HTTPS
  • sending incorrect HTTP parameters, triggering and logging the domain-exclusive violation message

These kludges also tend to get forgotten about, causing bugs further down the line.

Because of this, and because of the large number of publishers implementing Crossmark, we supply the script via CDN, instruct implementers to only use the CDN JavaScript. If implementers don’t do this, the dialog may behave in unexpected ways and we will not provide support.


The Crossmark dialog server generates a JWT every time it serves up a widget script. Because end-users see the script proxied through CloudFront CDN, this doesn’t incur any extra time to the end-user.

(For reference, it takes ~500ms to retrieve https://crossmark.crossref.org/widget/v2.0/widget.js but ~20ms to retrieve https://crossmark-cdn.crossref.org/widget/v2.0/widget.js)

The CDN will cache the widget code, and the JWT in it, for a given length of time. This appears in the JavaScript source something like:

document.CROSSMARK = {
  VERIFICATION: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXIiOiIyLjAuMTA2IiwiaWF0IjoxNTM5MzA0MzU4fQ.p2lhdJji6E8PZwnEoyf7NnTEoNlikLylkMZaOAZEO7U',
  ENDPOINT: 'https://crossmark.crossref.org/dialog',
  SCRIPT_VERSION: '2.0.106',
  STYLESHEET_URL: 'https://crossmark-cdn.crossref.org/widget/v2.0/style.css',
  LOGO_URL: 'https://crossmark-cdn.crossref.org/images/logo-crossmark.svg'

Plugging the VERIFICATION value into https://jwt.io/ we can see the following header and payload:

  "typ": "JWT",
  "alg": "HS256"
  "ver": "2.0.106",
  "iat": 1539304358

The “ver” records the version of the server, and the “iat” field gives the timestamp when the script was generated.

The JWT is sent to the dialog server, something like:


The server can then validate the JWT for tampering and record which version and timestamp of the widget was used. This can help us debug issues users are having, and ensure that they are implementing Crossmark correctly when responding to support tickets. If a support ticket is raised and our logs show that the timestamp has drifted, or they’re using the wrong version, there’s a good chance that it was copied and pasted, and may not include recent bugfixes.