EXTJWT command for integrating external web services#547
EXTJWT command for integrating external web services#547ItsOnlyBinary wants to merge 12 commits intoircv3:masterfrom
Conversation
Co-Authored-By: Kyle Fuller <[email protected]>
Co-Authored-By: Sadie Powell <[email protected]>
Having the verify url within the token would encourage implementations to use the url without verifying its trusted, allowing the spoofing of tokens. The verify url should be a pre-shared component for trust.
|
Reasoning behind removing the Having the verify url within the token would encourage implementations to use the url without verifying its trusted, allowing the spoofing of tokens. The verify url should be a pre-shared component for trust, just like the key would be pre-shared. With the url having the advantage of not actually sharing the key, so that the host of the third party service could not actually generated trusted tokens. |
|
Our implementation is updated to match the new pull request. |
|
Can we get an audit on implementations for this. Those I'm aware of:
Anyone else? Particularly would be nice to see clients, with examples of it being used. |
|
@sadiepowell @k4bek4be @slingamn thoughts on whether this should be merged as a draft? (needs editing to reflect that) AFAIK no client implements this other than kiwi, but any insight on how widely this is used on your servers? |
|
I'm happy to see this merged as a draft. We have a few users who are using this with Kiwi. I'm not aware of any other client implementations. |
|
I also support merging this as a draft. I don't have any concrete feedback from operators to report. |
skizzerz
left a comment
There was a problem hiding this comment.
Before we merge as draft, I took a look and there are a handful of issues I see with the spec as-written.
I'm not particularly happy with sub being the user's nickname (an ephemeral identifier that is very easy for the end user to change), but not every network has accounts, and for those that do, there's no guarantee an accountname is stable either. As such, I can't think of anything better. We may want to expand sub to allow for other identifiers however if the implementation has something more stable they'd wish to use. e.g. an account ID.
Note: I didn't modify the examples in my suggestions since there's no consensus on moving forward with them yet. If we decide to rename some of these claim names, then examples should be updated accordingly.
| The client will send at minimum `EXTJWT *` to the server to request a new JWT token. The server MUST then reply with the above response syntax with the `requested_target` and `service_name` defaulting to `*` if they were not provided in the request. The JWT token MUST contain the following claims that are relevant to the client at that time: | ||
|
|
||
| * `exp` Number; Unix timestamp for when this token expires. See below for notes on the expiry claim. | ||
| * `iss` String; The server name that generated this token. |
There was a problem hiding this comment.
| * `iss` String; The server name that generated this token. | |
| * `iss` String; The server or network name that generated this token. |
Networks that implement server hiding may wish to mask exactly which server produced a given JWT, or find that it isn't necessary to identify specific servers and prefer to have a stable issuer regardless of which server the user connected to.
There was a problem hiding this comment.
Using the network name is an acceptable alternative but FWIW in our implementation on networks that hide server names we use the masked server name (like "irc.example.com") here instead of the actual server name.
There was a problem hiding this comment.
should the masked/common server name be the default here (eg irc.example.com). for 3 party services wanting to support multiple networks having the common name would be much more useful than a specific server. The other option would be to have both.
|
|
||
| If the command sent by the client includes a service name, Eg. `EXTJWT * jitsi`, the server MUST then reply with the service name as its `service_name` parameter, along with the JWT token containing the above claims and also the following claims relevant to the service: | ||
|
|
||
| * `service` String; The configured service name that can be used to verify the token, with either a pre-shared key or url. |
There was a problem hiding this comment.
| * `service` String; The configured service name that can be used to verify the token, with either a pre-shared key or url. | |
| * `aud` String or []String; The configured service names or URIs that the token is intended for. |
aud is a standard claim type and service was duplicative of that standard audience claim. Let's just use the standard one instead of inventing our own. Expanded to allow either a string or an array of strings per JWT spec, and in case the service_name identifies multiple backend services the JWT should be valid for.
| If the command sent by the client includes a channel name, Eg. `EXTJWT #channel`, the server MUST then reply with the channel name as its `requested_target` parameter, along with the JWT token containing the above claims and also the following claims relevant to the channel at that time: | ||
|
|
||
| * `channel` String; The channel name this token is related to. | ||
| * `joined` Number; Unix timestamp of the time at which the client joined the channel. 0 if not joined. 1 if no timestamp is available. |
There was a problem hiding this comment.
| * `joined` Number; Unix timestamp of the time at which the client joined the channel. 0 if not joined. 1 if no timestamp is available. | |
| * `joined` ?Number; Unix timestamp of the time at which the client joined the channel. `null` if not joined. 0 if no timestamp is available. |
Similar to account, we can make values nullable so trying to do that to indicate lack of value makes more sense than identifying special sentinel values.
| * `exp` Number; Unix timestamp for when this token expires. See below for notes on the expiry claim. | ||
| * `iss` String; The server name that generated this token. | ||
| * `sub` String; The nick of the client that requested this token. | ||
| * `account` String; The account name of the user that requested this token. Empty if not available. |
There was a problem hiding this comment.
| * `account` String; The account name of the user that requested this token. Empty if not available. | |
| * `account` ?String; The account name of the user that requested this token. `null` if not available. |
JSON allows null values, and JWT allows any JSON values. Making these values nullable to designate a lack of value rather than designating certain strings as "special" makes a lot more sense to me.
There was a problem hiding this comment.
My concern with this is adding complexity in other languages, while json supports null using it could add unneeded complexity in languages with strict type handling.
There was a problem hiding this comment.
Such as? I cannot think of a single major language that would have an issue with this. Anyone implementing this would be using a JSON parsing library rather than handrolling a parser, and all mainstream JSON parsing libraries in existence support null just fine, mapping it into whatever that language supports.
If you mean extra complexity checking for null vs a value, that complexity already existed; it just wasn't encoded into the type system but rather as special values. Which is worse because it's easy to forget or incorrectly write those checks, whereas the type system enforcing you to check for null (in languages that enforce that) makes it impossible for you to forget or implement it incorrectly. At the very least, doing it wrong will result in obvious runtime behavior (crashes/exceptions) rather than silent corruption.
There was a problem hiding this comment.
My concern with this is adding complexity in other languages, while json supports null using it could add unneeded complexity in languages with strict type handling.
For what its worth most languages like this will represent such a value using the native null value or in the case of something like Rust, Option<String>.
|
Server support: I know there is small amount of users using EXTJWT in UnrealIRCd. I'll be trying to get some more precise numbers. |
|
Kiwi IRC currently has 3 main plugins that use EXTJWT they are:
Other network admins do appear to have also created quite complex account/profile systems that also use EXTJWT tokens to link different pieces. I hope these demonstrate the usefulness of this spec for linking IRC with 3rd party services |
|
I really like this spec and see great potential for use if paired with an external-service discovery mechanism. Also, (it might be too late for this, given several implementations exists, but I'm proposing anyway), |
|
re. the use of |
|
Given its still a draft spec I'm fine with breaking compatibility to make the IRCv3 implementation behave more like the upstream spec, if necessary server implementations can emit both keys for a period. |
|
There's no way to make the nullable field changes compatible since they use the same key names. |
|
Since there's no prefixing here (this spec predates ISUPPORT prefixing, no need to add it now imo) there's not much to add in a "Notes for implementing work-in-progress version" section. The wip key is also already set. So this is fine to merge once a decision is made on the other suggestions. I'd probably favour not changing the nullable fileds. The |
|
The more I look into this spec the less I like it. While I'm not going to expend any additional energy to block it from being merged or correct it, I think this is probably better off left as a vendor extension (unprefixed for historical reasons) and something goes back to the drawing board from square 1 with a better eye on security (and a different command name/ISUPPORT token). It attempts to implement authn and authz and fails at both because it tries to be too generic without any consideration of the threat models it is facing or that external services making use of this face.
While I do not mean to disparage the writers of this spec, it's fairly clear that minimal to no research was done on the federated authn/authz front. Please look at the security challenges that SAML and OIDC solve and how they solve them, or heck even OAuth in general with their Bearer tokens. I'm not saying this needs to replicate those precisely, but it should not regress in basic ways that make the spec inflexible and largely unusable in general, despite supposedly being general purpose. As mentioned before, I'm not going to expend any additional energy on fighting this, so please do not expect further replies in this thread from me. |
InspIRCd supports the |
|
I removed vfy after reading #341 (comment) I explain how a pre-shared verify url can be used in "external service verifies that the token has not been tampered with by one of two methods" this wording really should have security considerations notice, suggesting that both should be done and the risks of only using pre-shared password. I will do some research into hardening and improving this spec. I am fully open to specific suggestions and wording. |
As prawnsalad has stepped back from IRC development and I have taken over Kiwi IRC development. I cannot allow this ircv3 specification to be abandoned as Kiwi IRC uses it for quite a few plugins. (jitsi conferencing, file uploads, account avatar uploads)
So I have also forked #341 and updated based on comments from within the previous pull-request.