ArenaNet Staff Daniel Snider.6241 Posted May 21, 2019 ArenaNet Staff Share Posted May 21, 2019 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/cats Authorization: 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/cats Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3YlRodVdNNGExMUduZlpYSTdaa 0pHck52SVVPUWhMejZHTXpOeE9TUC1rIiwiaWF0IjoxNTU4Mzk3OTUwLCJleHAiOjE1NzczMDYwOTYsInBlcm1pc3Npb25zI jpbInByb2dyZXNzaW9uIiwiYWNjb3VudCIsInVubG9ja3MiXSwidXJscyI6WyIvdjIvY2hhcmFjdGVycy9NeSUyMENvb2wlM jBDaGFyYWN0ZXIiLCIvdjIvYWNjb3VudC9ob21lL2NhdHMiXX0.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 More sharing options...
Illconceived Was Na.9781 Posted May 21, 2019 Share Posted May 21, 2019 Thanks for the post, @"Daniel Snider.6241" I love the regular communication about plans and changes. I'm looking forward to seeing how the fan-devs use the subtoken. Sounds very promising. Link to comment Share on other sites More sharing options...
DragonFury.6243 Posted May 21, 2019 Share Posted May 21, 2019 I am loving these changes Love the communications Link to comment Share on other sites More sharing options...
Karasu.9483 Posted May 21, 2019 Share Posted May 21, 2019 This is a ridiculously awesome and underrated update. Thank you so much for your work in continuing to expand and your support of the API. Link to comment Share on other sites More sharing options...
ArenaNet Staff Daniel Snider.6241 Posted May 21, 2019 Author ArenaNet Staff Share Posted May 21, 2019 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 More sharing options...
Elrey.5472 Posted May 22, 2019 Share Posted May 22, 2019 Can we create endless subtokens? Link to comment Share on other sites More sharing options...
StevenL.3761 Posted May 22, 2019 Share Posted May 22, 2019 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 More sharing options...
ArenaNet Staff Daniel Snider.6241 Posted May 22, 2019 Author ArenaNet Staff Share Posted May 22, 2019 > @"Elrey.5472" said: > Can we create endless subtokens? No. I decided to start with a required expire time and a maximum. I figured the endpoint should start more restrictive, then wait to see if we need to loosen the restrictions depending on app developers' needs. Link to comment Share on other sites More sharing options...
ArenaNet Staff Daniel Snider.6241 Posted May 22, 2019 Author ArenaNet Staff Share Posted May 22, 2019 > @"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 More sharing options...
StevenL.3761 Posted May 30, 2019 Share Posted May 30, 2019 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 More sharing options...
ArenaNet Staff Daniel Snider.6241 Posted May 31, 2019 Author ArenaNet Staff Share Posted May 31, 2019 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 More sharing options...
StevenL.3761 Posted June 1, 2019 Share Posted June 1, 2019 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/createsubtoken let 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 More sharing options...
StevenL.3761 Posted June 4, 2019 Share Posted June 4, 2019 @"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 More sharing options...
StevenL.3761 Posted June 28, 2020 Share Posted June 28, 2020 Is it possible to make URL restrictions less strict? If I create a token with `urls=/v2/characters` then I can get `/v2/characters?ids=all` but not a subset like `/v2/character/My Awesome Character`. Link to comment Share on other sites More sharing options...
memausz.7264 Posted June 29, 2020 Share Posted June 29, 2020 Why are all the third party websites still having outdated utility/spec descriptions? Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now