-
Notifications
You must be signed in to change notification settings - Fork 79
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
EXTJWT command for integrating external web services #341
base: master
Are you sure you want to change the base?
Conversation
extensions/extjwt.md
Outdated
|
||
The client MAY send `EXTJWT` or `EXTJWT *` to the server to request a new JWT token. The server MUST then reply with `EXTJWT *` and a JWT token as its jwt_token parameter containing the following claims that are relevant to the client at that time: | ||
|
||
* `exp` Number; Unix timestamp for when this token expires. Usually less than 1 minute from the token generation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- UTC
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unix timestamp is consistent with other parts such as RPL_TOPICWHOTIME so we don't want to go changing that.
extensions/extjwt.md
Outdated
|
||
### The EXTJWT Command | ||
|
||
Syntax: `EXTJWT [channel]` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be: EXTJWT ( <channel> | * )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
extensions/extjwt.md
Outdated
|
||
* `channel` String; The channel name this token is related to. | ||
* `joined` Boolean; True if the client that requested this token is joined to the channel. | ||
* `time_joined` Number; The time in which the user joined the channel. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What should its value be if joined
is False?
The best solution would probably to merge join
and time_joined
as a single optional attribute, so the receiver of the JWT does not need to sanity-check this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think originally I preferred to be explicit with the claim names, but being more concise here would save a lot of space.
I can change this by dropping the time_joined
claim, changing joined
to contain the timestamp of when joined and setting it to 0 when not joined to the channel
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change has now been applied, good shout
extensions/extjwt.md
Outdated
|
||
#### Handling long responses | ||
|
||
In some cases the encoded token may be longer than the maximum line length allowed between the client and server. In this case, the first parameter of the response MUST be `*` to indicate that further data will follow. The final chunk of the response sent to the client MUST NOT include `*` as the first parameter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use the same mechanism as AUTHENTICATE
, for consistency between IRCv3 specs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the mechanism that CAP LS 302
uses, so there's consistency between that and EXTJWT at least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. As the CAP LS 302
way is much easier to implement, I agree this mechanism should be used.
extensions/extjwt.md
Outdated
* `channel` String; The channel name this token is related to. | ||
* `joined` Boolean; True if the client that requested this token is joined to the channel. | ||
* `time_joined` Number; The time in which the user joined the channel. | ||
* `modes` []String; An array of the channel modes the client has in this channel. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a way to disclose modes with arguments? eg. +I
to tell the mask that allows the user to be in that channel.
extensions/extjwt.md
Outdated
* `iss` String; The server name that generated this token. | ||
* `nick` 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. | ||
* `net_modes` []String; An array of user modes the IRCd may want to disclose. Eg, if the user is an operator. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some generic net modes should probably added to this spec.
extensions/extjwt.md
Outdated
|
||
Where the replied token is decoded into: | ||
~~~json | ||
{"exp":1529917513,"iss":"irc.example.org","nick":"somenick","account":"somenick","net_modes":["o"]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"o"
looks like a channel op, you should probably rename it. A non-single-letter name would be nice too (let's not repeat the mistakes of the past).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These modes are the user modes the IRC server has set. Ie. o
for operator. If an IRCd introduces named modes then the named modes will be placed in here too.
extensions/extjwt.md
Outdated
|
||
Where the replied token is decoded into: | ||
~~~json | ||
{"exp":1529917513,"iss":"irc.example.org","nick":"somenick","account":"","net_modes":[]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not allow "account": null
, or making that attribute optional?
Looks like a cool idea! Even if it does not get implemented by IRC daemons (or networks), this could be partially provided by (non-privileged) bots. |
extensions/extjwt.md
Outdated
|
||
Response syntax: `EXTJWT <requested_target> [*] <jwt_token>` | ||
|
||
The client MAY send `EXTJWT` or `EXTJWT *` to the server to request a new JWT token. The server MUST then reply with `EXTJWT *` and a JWT token as its jwt_token parameter containing the following claims that are relevant to the client at that time: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason to have two command syntax variants for a non-channel JWT (no parameters and *
)?
extensions/extjwt.md
Outdated
* `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. | ||
* `net_modes` []String; An array of user modes the IRCd may want to disclose. Eg, if the user is an operator. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bikeshed: net_modes
should be referred to as user_modes
and modes
(below) should be channel_modes
.
How should a server behave if there was an issue with generating the JWT for some reason? |
Is it useful to add a context parameter to the command so that JWTs can be generated with different secrets for integrating with multiple services? e.g. |
@SaberUK I could imagine that use case, yes. If I make the |
I like this, sounds like a nice way to let nets setup external services without giving db access and similar. From the looks of it, it's not useful for services being setup without the network's prior OK (agreement on the secret, etc), and that's intended? Will look at writing up an implementation of this in Ora. The |
I'm about to update this draft spec with some minor tweaks that's come up during testing since this was first implemented.
It has been mentioned by a few people that usage would be fairly limited since third parties would need to be configured with JWT secrets from the IRCd. To get around this I could add an optional
Advantages:
|
Co-Authored-By: Kyle Fuller <kyle@fuller.li>
What happens if a user forges a JWT and sets the "vfy" URL to something like, for example,
This would take the "iss" field as the first input, and the token as a whole as the second field.
|
|
||
Where the replied token is decoded into: | ||
~~~json | ||
{"exp":1529917513,"iss":"irc.example.org",vfy":"https://irc.example.org/extjwt?t=%s","sub":"testnick","account":"testnick","umodes":[],"channel":"#channel","joined":1529917501,"cmodes":["o"]} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
json's a tiny bit mangled here, should be ,"vfy"
instead of ,vfy"
|
Co-Authored-By: Sadie Powell <sadie@witchery.services>
As I mentioned on IRC last night, what do people think about sending the token using an |
I would be fine with that. That means you only need to specify an optional "issuer subdomain" and an optional "issuer verification path" which can both be static strings. |
I see some continued comments on IRC (both within IRCv3 and when discussing with some infosec friends) where the reason for this validation URL is misunderstood. I think it would be good to put some emphasis on only using the validation URL IF there is no possible shared secret. Most importantly, if there is a shared secret and it fails, I think that the validation URL MUST NOT attempted, as the shared secret is a more secure method and should take higher priority. |
Additionally, some conversations that prawnsalad and I had about this:
|
Discussion on IRC brought up usage of an asymmetric key, with the public version stored in a standardized location in the issuer. This resolves both the issue of the external service not having a shared secret and the issue of the client being able to spoof the endpoint used for authentication. |
What is the use case for including the channel join time in the token? |
From discussion in #kiwiirc: we're tentatively proposing that server implementations that do not store channel join time information can send |
What is the reason for this change exactly? It's not hard to update an existing implementation to store the join time if necessary. |
I'd prefer not to add it to my implementation, given that there is no use case for it right now. |
Clarification questions that came up during Dan's implementation:
|
JWT tokens allow you to use any algo your implementation can support. As long as you can create + verify your own token, you're all good.
A default should be used, yes. This default would be the most used as clients making use of EXTJWT wouldn't know what services your IRCd has running or what name to use for them unless the network has a dedicated client for it. |
Other than the service being able to cache a pub key from the issuer, what other benefit would this have? Both algo types will need a request back to the issuer either for the pub key or verification as far as I understood. Also to note, the external service is not required to know the shared secret for a token. While services run by the same IRCd network may share the secret which saves the verification request trip, third parties can make the verification request without knowing any secrets. |
For pubkey based verification you can just put a static key in a directory. For verifying the JWT itself, you'd have to implement something server side. I think a majority of hosts would rather have a static file option. |
Can we add the supported services to the ISUPPORT token in any way? Something like, |
Any explanation for this example, please? |
I have created an implementation for the EXTJWT command. I'm supporting HS, ES and RS type tokens, with method and key/password selectable per service. Users on our network are already using the The specification does not mention any error handling. That's what I've devised:
The |
This draft is now shipped as optional feature with unrealircd 6.0.0. |
This spec provides a way for web services hosted externally to an IRC server to authenticate users that are connected to the IRC server by making use of the standard JWT tokens (https://jwt.io/).
This allows a web service to do things such as:
For a more indepth example we could use the free audio/video conference service - Jitsi Meet. This service has built in JWT verification in that an application can send a user to a URL that contains a JWT token, and if the Jitsi Meet server verifies this token successfully, the user is granted access to that conference room.
When an IRC client wants to join a conference room, it would first call
EXTJWT #testchannel
to receive a JWT token from the IRCd. The client would then open a browser window navigating to the Jitsi Meet URL while passing that token. It is up to the client to decide how and where to use this token, eg. via a "Jitsi Call" button for example.