-
Notifications
You must be signed in to change notification settings - Fork 82
EXTJWT command for integrating external web services #547
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
Open
ItsOnlyBinary
wants to merge
12
commits into
ircv3:master
Choose a base branch
from
ItsOnlyBinary:extjwt
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
e2e85ab
Create extjwt.md
prawnsalad 41c6187
Update extjwt.md
prawnsalad b53eb93
Example syntax update; Combine joined+time_joined claims
prawnsalad d1ad8d1
Replacing the nick claim with the JWT standard sub (subject) claim
prawnsalad 51a288a
Versioning support
prawnsalad 66c11e1
Notes on token expiration
prawnsalad 4a390fa
Optional verify URL; Optional service names; *modes claim renamed;
prawnsalad 6be574e
vfy 403 > 401
prawnsalad 6ceab95
Update extensions/extjwt.md
prawnsalad f3facfb
Channel `joined` claim to be 1 if no timestamp is available
prawnsalad f5a1879
Define possible errors
ItsOnlyBinary 7e0ce18
Remove vfy claim
ItsOnlyBinary File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| --- | ||
| title: IRCv3 `extjwt` extension | ||
| layout: spec | ||
| work-in-progress: true | ||
| copyrights: | ||
| - | ||
| name: Darren Whitlen | ||
| period: 2018 | ||
| email: darren@kiwiirc.com | ||
| --- | ||
| ## Introduction | ||
|
|
||
| IRC networks and clients often provide external web hosted services for their user base such as forums, wikis and pastebins. However, without extra development work on the IRC network and the external service they usually require separate user authentication. | ||
|
|
||
| This feature provides a way for the external service to verify that a user is connected with specific permissions and / or is joined to any channels, removing the need for any development ties between the IRC network and the external service such as using XMLRPC or custom bots or shared database access. | ||
|
|
||
| Once in use, this: | ||
| 1. Makes it easier to deploy an external service as it does not need access to your IRC server. | ||
| 2. Improves security in that a misconfigured or vulnerable external service cannot impact the IRC network or user accounts. | ||
| 3. Provides a common method to verify user status on a channel (joined, channel modes) while using well known libraries and methods that are available for many languages and frameworks (JWT). | ||
|
|
||
| ### How the verification works | ||
|
|
||
| The IRC network generates signed JWT tokens and sends them to the client. The client may use this token to open an external service with the token in its URL. | ||
|
|
||
| The JWT token (https://jwt.io/) is a base64 encoded JSON payload that is signed with a secret string. The JSON payload consists of known claims that include: | ||
| * `exp` `1529917513` Expiry time for this token. | ||
| * `iss` `"irc.example.org"` The server name that generated this token. | ||
| * `sub` `"somenick"` The nick of the user that generated this token. | ||
| * `account` `"somenick"` The account name of the user that generated this token. Empty if not logged in. | ||
| * `umodes` `["o"]` User modes the IRCd wishes to disclose. Eg, if the user is an operator. | ||
|
|
||
| When an external service is opened with this token in its URL, the external service verifies that the token has not been tampered with by one of two methods: | ||
| 1. If the external service has a pre-shared secret for this IRC network, it can now verify the token directly. | ||
| 2. The external service can make a HTTP GET request to a pre-shared URL, replacing `%s` with the token string. The request MUST be responded to with a HTTP 200 status if the token has been verified, or a HTTP 401 status if the token is invalid. | ||
|
|
||
| Once successfully verified, the external service can then use the available claims in the token to create any required user accounts and log the user in automatically. | ||
|
|
||
| ## Usage | ||
|
|
||
| If the feature is available on the IRC server, the `EXTJWT=1` token pair is added to its ISUPPORT list where `1` denotes the version of this feature. Currently this is the only version of EXTJWT, version `1`. | ||
|
|
||
| Only one new command is introduced in this extension, `EXTJWT`. | ||
|
|
||
| ### The EXTJWT Command | ||
|
|
||
| Syntax: `EXTJWT ( <channel> | * ) [service_name]` | ||
|
|
||
| Response syntax: `EXTJWT <requested_target> <service_name> [*] <jwt_token>` | ||
|
|
||
| The `service_name` is an optional name for what the token is being requested for. Eg, `EXTJWT * forum.example.org`. The server MAY take this service name to sign its token using different secrets. It defaults to `*` if not provided. | ||
|
|
||
| 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. | ||
| * `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. | ||
| * `umodes` []String; An array of user modes the IRCd may want to disclose. Eg, if the user is an operator. | ||
|
|
||
| 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. | ||
|
|
||
| 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. | ||
| * `cmodes` []String; An array of the channel modes the client has in this channel. | ||
|
|
||
| The IRC server MUST include the above claims but MAY include any extra claims. | ||
|
|
||
|
|
||
| #### 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 third 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 this extra `*` parameter. | ||
|
|
||
| Eg: | ||
| ~~~ | ||
| [C -> S] EXTJWT #channel | ||
| [S -> C] EXTJWT #channel * * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJ0ZXN0bmljayIsImFjY291bnQiOiJ0ZXN0bmljayIsInVtb2RlcyI6W10sImNoYW5uZWwiOiIjY2hhbm5lbCIsImpvaW5lZCI6MTUyOTkxNzUwMSwiY21v | ||
| [S -> C] EXTJWT #channel * * ZGVzIjpbIm8iXSwiY2xhaW0xIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW0yIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW0zIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW00Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW01Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW02Ijoic29tZ | ||
| [S -> C] EXTJWT #channel * SBsb25nIHZhbHVlIiwiY2xhaW03Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW04Ijoic29tZSBsb25nZXIgdmFsdWUgdG8gbWFrZSBzdXJlIHRoaXMgdG9rZW4gaXMgdG9vIGxvbmcgdG8gc2VuZCBvbiBvbmUgSVJDIDUxMiBjaGFyYWN0ZXIgbGluZSJ9.wxRb7lH9OjENg_dTmPrDglBsN3Z17g1eEGJdp9Jsbqg | ||
| ~~~ | ||
|
|
||
| #### Errors | ||
|
|
||
| Along with numeric errors where appropriate this specification defines a few errors using [standard-replies](https://ircv3.net/specs/extensions/) with example plain text descriptions. | ||
|
|
||
| `ERR_NEEDMOREPARAMS` (461) - Not enough parameters sent to EXTJWT. | ||
|
|
||
| `ERR_NOSUCHCHANNEL` (403) - Requested channel does not exist. | ||
|
|
||
| `:irc.example.com FAIL EXTJWT NO_SUCH_SERVICE :You specified an invalid JSON Web Token profile` - Token requested for a service profile that does not exist. | ||
|
|
||
| `:irc.example.com FAIL EXTJWT UNKNOWN_ERROR :Failed to generate JSON Web Token` - There was an error generating the token. | ||
|
|
||
| #### Notes on the token expiry claim | ||
|
|
||
| When generating a token, the expiry (exp) claim must be configured with enough length of time for the token to be used but also be short enough that the token does not last indefinately, leaving the user with a valid token after the user has left a channel or changed its network modes. | ||
|
|
||
| 30 seconds is usually enough time for the client to receive the token from the `EXTJWT` command and then open the external service webpage, however, non-webpage based services may require a longer expiration depending on its implementation. | ||
|
|
||
| ## Examples | ||
|
|
||
| All examples may be verified using the secret of "your-256-bit-secret". | ||
|
|
||
| #### A client logged into the IRC server with operator privileges | ||
| ~~~ | ||
| [C -> S] EXTJWT * | ||
| [S -> C] EXTJWT * * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InNvbWVuaWNrIiwiYWNjb3VudCI6InNvbWVuaWNrIiwidW1vZGVzIjpbIm8iXX0.wZbYLX4rgDDB4svLQIsx5jq5_Dc0csdqgamVsgocOas | ||
| ~~~ | ||
|
|
||
| Where the replied token is decoded into: | ||
| ~~~json | ||
| {"exp":1529917513,"iss":"irc.example.org","sub":"somenick","account":"somenick","umodes":["o"]} | ||
| ~~~ | ||
|
|
||
| #### A client connected to the IRC server without a registered account or operator privileges | ||
| ~~~ | ||
| [C -> S] EXTJWT * | ||
| [S -> C] EXTJWT * * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InNvbWVuaWNrIiwiYWNjb3VudCI6IiIsInVtb2RlcyI6W119.i_ak4qvb1BPdH0a0HyRNTz036rHE2lGrZ17SQV3LAFE | ||
ItsOnlyBinary marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ~~~ | ||
|
|
||
| Where the replied token is decoded into: | ||
| ~~~json | ||
| {"exp":1529917513,"iss":"irc.example.org","sub":"somenick","account":"","umodes":[]} | ||
| ~~~ | ||
|
|
||
| #### A client logged into the IRC server and has channel operator privileges on a channel | ||
| ~~~ | ||
| [C -> S] EXTJWT #channel | ||
| [S -> C] EXTJWT #channel * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InRlc3RuaWNrIiwiYWNjb3VudCI6InRlc3RuaWNrIiwidW1vZGVzIjpbXSwiY2hhbm5lbCI6IiNjaGFubmVsIiwiam9pbmVkIjoxNTI5OTE3NTAxLCJjbW9kZXMiOlsibyJdfQ.A6tYn5w2-yNQ3Ni-W8EMaCmtssc4EG-M_OTI4sf-yUA | ||
| ~~~ | ||
|
|
||
| Where the replied token is decoded into: | ||
| ~~~json | ||
| {"exp":1529917513,"iss":"irc.example.org","sub":"testnick","account":"testnick","umodes":[],"channel":"#channel","joined":1529917501,"cmodes":["o"]} | ||
| ~~~ | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.