Jump to content
  • Sign Up

API update - May 20 2019


Recommended Posts

  • ArenaNet Staff

Hello all,

I put together a quick change to the API to allow some more fine-tuned control over sharing API keys a few weeks ago, and I had a chance to deploy it today. I have added an endpoint for creating what I'm calling "subtokens".

Recent API Updates


First, here is the change in list format:

  • Added the /v2/createsubtoken endpoint

Subtokens


As a warning: this change's uses are niche.

A subtoken is a special API key that can be used anywhere a normal API key can be used. It is simply a wrapper around a regular API key with reduced permissions. It can be created by accessing /v2/createsubtoken with several options:

  • Subset of permissions (e.g. account, inventories)
  • Expire time
  • List of urls that can be accessed (optional: if no urls are provided, then all urls are allowed)

Here is an example that shows the full functionality:

GET https://api.guildwars2.com/v2/createsubtoken?permissions=account&expire=2019-12-25%2012:34:56&urls=/v2/characters/My%20Cool%20Character,/v2/account/home/catsAuthorization: Bearer MY_API_KEY

The API will respond with:

{  "subtoken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3YlRodVdNNGExMUduZlpYSTdaa0pHck52  SVVPUWhMejZHTXpOeE9TUC1rIiwiaWF0IjoxNTU4Mzk3OTUwLCJleHAiOjE1NzczMDYwOTYsInBlcm1pc3Npb25zIjpbIn  Byb2dyZXNzaW9uIiwiYWNjb3VudCIsInVubG9ja3MiXSwidXJscyI6WyIvdjIvY2hhcmFjdGVycy9NeSUyMENvb2wlMjBD  aGFyYWN0ZXIiLCIvdjIvYWNjb3VudC9ob21lL2NhdHMiXX0.UdLlafgo8lxkb1Hn88paZT83aw_9mHEYVZJLDgObNSc"}

I can then see what cats I have unlocked with this large subtoken

GET https://api.guildwars2.com/v2/account/home/catsAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3YlRodVdNNGExMUduZlpYSTdaa0pHck52SVVPUWhMejZHTXpOeE9TUC1rIiwiaWF0IjoxNTU4Mzk3OTUwLCJleHAiOjE1NzczMDYwOTYsInBlcm1pc3Npb25zIjpbInByb2dyZXNzaW9uIiwiYWNjb3VudCIsInVubG9ja3MiXSwidXJscyI6WyIvdjIvY2hhcmFjdGVycy9NeSUyMENvb2wlMjBDaGFyYWN0ZXIiLCIvdjIvYWNjb3VudC9ob21lL2NhdHMiXX0.UdLlafgo8lxkb1Hn88paZT83aw_9mHEYVZJLDgObNSc

and get normal results.

The request will be rejected if:

  • The reduced permissions do not meet the permission requirements of the endpoint
  • The subtoken time is expired
  • The request url does not match the restricted url set (unless there are no url restrictions)
  • The original API key which was used to create the subtoken is deleted

Subtoken uses


As I admitted earlier, there aren't a huge amount of uses for a subtoken. Here are the two use-cases I considered while making this change:

First and foremost, subtokens lets an app (App 1) accept & store an API key from a player and then pass that API key on to another app (App 2) with more control over what App 2 can do with the player's key.

The other case is for savvy users who want more control over what they share with their API key. They can use the endpoint to generate subtokens to hand over to apps with, e.g. expire times or restrictions to certain character endpoints.

I'd love to hear thoughts and feedback for this change, as well as any bug reports.

Thanks!Snider

EDIT: Added a bit about deleting the original API Key

Link to comment
Share on other sites

  • ArenaNet Staff

A quick update:

Some users have already pointed out some bugs with the new /v2/createsubtoken endpoint. Those have been fixed.I have also changed /v2/tokeninfo to understand subtokens, given a recent schema version parameter (e.g. ?v=latest).

If you see any more issues, let me know. Thanks!

Link to comment
Share on other sites

Hey I'd be careful with allowing GET with createsubtoken because it has different semantics that (maybe some) clients use to decide whether to cache the response.

In general a GET should be idempotent (asking a question should not change the answer).

Link to comment
Share on other sites

  • ArenaNet Staff

@StevenL.3761 said:Hey I'd be careful with allowing GET with createsubtoken because it has different semantics that (maybe some) clients use to decide whether to cache the response.

In general a GET should be idempotent (asking a question should not change the answer).

You're right, it really should be POST. I chose GET because for API internal reasons POST is much harder and I wanted to get a fast turnaround on this feature.

That said, I think GET is OK here because it's still a stateless call: the subtoken parameters are just stored in the subtoken itself. Nothing is written and no state is modified on the API server-side when /v2/createsubtoken is accessed.

Link to comment
Share on other sites

Yep that sounds totally fine then.

I'm implementing access to this endpoint now and I noticed that it's possible to create a token that has no permissions. It's also possible to create a token with an "exp" that is before its "iat".

Example: GET /v2/createsubtoken?expire=2018-05-30T13:08:13

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJZZEVvTnRjQkJ1YnF5UmxoZWdPZC1iWGktMUxfd3NxQm1aV0x5YTlXd09ZIiwiaWF0IjoxNTU5MjIxNjkzLCJleHAiOjE1Mjc2ODU2OTMsInBlcm1pc3Npb25zIjpbXX0._Jsmtm8bUkqIWthjcIEG8eNAfM4Npp8x5Br5rsglMvI

Not even /v2/tokeninfo accepts this token. I'm not sure if the service should be handing out tokens that are practically useless?

Link to comment
Share on other sites

  • ArenaNet Staff

Hmm. Some non-static endpoints require an access key but do not require any permissions. Off the top of my head, I believe /v2/tokeninfo doesn't require any permissions. Maybe that endpoint was built that way because it assumes account is always set.


I'm not sure why you'd want to generate a token that expires in the past. I could have it error when exp < iat, but there's not a whole lot of benefit other than helpful sanity checking for the user of the endpoint.


Also, if I have time at some point (and I remember), I'll put some cache-control properties in the response headers to tell the client not to cache the endpoint since it does change on every refresh due to iat being encoded in the response.

Link to comment
Share on other sites

Thanks for the detailed response.

Off the top of my head, I believe /v2/tokeninfo doesn't require any permissions.

I've been trying some things and I've seen tokeninfo return 403 Forbidden under a few circumstances:

  • Token is expired (exp < now())
  • "urls" is used but does not include "/v2/tokeninfo"
  • Race condition?

I'm not sure about the last one but if you do:

let subtoken = GET /v2/createsubtokenlet tokeninfo = GET /v2/tokeninfo?access_token={subtoken}

The second call sometimes fails. Adding a delay between the first and second call seems to help. I don't know how that's possible if the first call does not write state?

Link to comment
Share on other sites

@"Daniel Snider.6241" is it possible that /v2/createsubtoken and /v2/tokeninfo run on different machines with different system clocks? Is it possible that those clocks are not synchronized? I often get "Invalid access token" from tokeninfo immediately after the subtoken is created. If there's no state then I'm guessing you use the "iat" claim to check if the token is valid... or some weird signing algorithm that's also time-sensitive.

Link to comment
Share on other sites

  • 1 year later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...