From e2e85ab40d994def2b422b9e81faeec6e3cd5dd9 Mon Sep 17 00:00:00 2001 From: Darren Date: Sat, 21 Jul 2018 21:11:35 +0100 Subject: [PATCH 01/12] Create extjwt.md --- extensions/extjwt.md | 111 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 extensions/extjwt.md diff --git a/extensions/extjwt.md b/extensions/extjwt.md new file mode 100644 index 000000000..6678cccf2 --- /dev/null +++ b/extensions/extjwt.md @@ -0,0 +1,111 @@ +--- +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 IRC network to offer proof that a user is connected with specific permissions and / or is joined to any channels, so that the external service can use this proof to authenticate users without 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 proof works + +The IRC network creates the proof by generating JWT tokens and sending 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 an encoded JSON payload that is signed with a shared secret string between the IRC server and the external service. The JSON payload consists of known properties (claims) that include: +* `exp` `1529917513` Expiry time for this token. Usually less than 1 minute from the token generation. +* `iss` `"irc.example.org"` The server name that generated this token. +* `nick` `"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. +* `net_modes` `["o"]` User modes the IRCd wishes to disclose. Eg, if the user 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 using its pre-configured secret string and can then use the available claims to create any required user accounts and log the user in automatically. + +## Usage + +If the feature is available on the IRC server, the `EXTJWT` token is added to its ISUPPORT list. + +Only one new command is introduced in this extension, `EXTJWT`. + +### The EXTJWT Command + +Syntax: `EXTJWT [channel]` + +Response syntax: `EXTJWT [*] ` + +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 second 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. +* `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. + +The command must also support a single parameter of a channel name. Eg. `EXTJWT #channel`. The server must then reply with the channel name as its first parameter and 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` 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. + +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 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. + +Eg: +~~~ +[C -> S] EXTJWT #channel +[S -> C] EXTJWT #channel * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJ0ZXN0bmljayIsImFjY291bnQiOiJ0ZXN0bmljayIsIm5ldF9tb2RlcyI6W10sImNoYW5uZWwiOiIjY2hhbm5lbCIsImpvaW5lZCI6dHJ1ZSwidGltZV9qb2luZWQiOjE1Mjk5MTc1MDEsIm1vZGVzIjpbIm8iXSwiY2xhaW0xIjoic29tZSBsb25nIHZhbHVlIiw +[S -> C] EXTJWT #channel * iY2xhaW0yIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW0zIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW00Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW01Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW02Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW03Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW04Ijoic29tZSBsb25nZXIgdmFsdWUgdG8gbWFrZSBzdXJlIHRoaXMgdG9rZW4gaXMgdG9vIGxvbmc +[S -> C] EXTJWT #channel gdG8gc2VuZCBvbiBvbmUgSVJDIDUxMiBjaGFyYWN0ZXIgbGluZSJ9.c9_pKy1jFsDeevja7o6spPa-JUyzg4z4k3A65fxwZWw +~~~ + +## 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.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJzb21lbmljayIsImFjY291bnQiOiJzb21lbmljayIsIm5ldF9tb2RlcyI6WyJvIl19.NREHeoO-aewAry44erDgCHuVmUW9zyJjG05mJYCXXfs +~~~ + +Where the replied token is decoded into: +~~~json +{"exp":1529917513,"iss":"irc.example.org","nick":"somenick","account":"somenick","net_modes":["o"]} +~~~ + +#### A client connected to the IRC server without a registered account or operator privileges +~~~ +[C -> S] EXTJWT * +[S -> C] EXTJWT * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJzb21lbmljayIsImFjY291bnQiOiIiLCJuZXRfbW9kZXMiOltdfQ.Vkm2XJXHz6rkq-R93fJUp88kNmAU9J65w46ZsQLjJrY +~~~ + +Where the replied token is decoded into: +~~~json +{"exp":1529917513,"iss":"irc.example.org","nick":"somenick","account":"","net_modes":[]} +~~~ + +#### A client logged into the IRC server and has channel operator privileges on a channel +~~~ +[C -> S] EXTJWT #channel +[S -> C] EXTJWT #channel eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJ0ZXN0bmljayIsImFjY291bnQiOiJ0ZXN0bmljayIsIm5ldF9tb2RlcyI6W10sImNoYW5uZWwiOiIjY2hhbm5lbCIsImpvaW5lZCI6dHJ1ZSwidGltZV9qb2luZWQiOjE1Mjk5MTc1MDEsIm1vZGVzIjpbIm8iXX0.jd1VHnEN02mSw4g2BfB-gYOooktpua2HSd9qtcUBZ4M +~~~ + +Where the replied token is decoded into: +~~~json +{"exp":1529917513,"iss":"irc.example.org","nick":"testnick","account":"testnick","net_modes":[],"channel":"#channel","joined":true,"time_joined":1529917501,"modes":["o"]} +~~~ From 41c6187039b8d4721644e3e870fbfda9aeb9e8eb Mon Sep 17 00:00:00 2001 From: Darren Date: Sat, 21 Jul 2018 21:54:03 +0100 Subject: [PATCH 02/12] Update extjwt.md --- extensions/extjwt.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index 6678cccf2..da0a52f2a 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -21,7 +21,7 @@ Once in use, this: ### How the proof works -The IRC network creates the proof by generating JWT tokens and sending them to the client. The client may use this token to open an external service with the token in its URL. +The IRC network creates the proof by generating signed JWT tokens and sending 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 an encoded JSON payload that is signed with a shared secret string between the IRC server and the external service. The JSON payload consists of known properties (claims) that include: * `exp` `1529917513` Expiry time for this token. Usually less than 1 minute from the token generation. @@ -42,9 +42,9 @@ Only one new command is introduced in this extension, `EXTJWT`. Syntax: `EXTJWT [channel]` -Response syntax: `EXTJWT [*] ` +Response syntax: `EXTJWT [*] ` -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 second parameter, containing the following claims that are relevant to the client at that time: +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. * `iss` String; The server name that generated this token. @@ -52,18 +52,18 @@ The client may send `EXTJWT` or `EXTJWT *` to the server to request a new JWT to * `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. -The command must also support a single parameter of a channel name. Eg. `EXTJWT #channel`. The server must then reply with the channel name as its first parameter and the JWT token containing the above claims and also the following claims relevant to the channel at that time: +The command MUST also support a single parameter of a channel name. Eg. `EXTJWT #channel`. The server MUST then reply with the channel name as its requested_target parameter, 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` 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. -The IRC server must include the above claims but may include any extra claims. +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 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. +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. Eg: ~~~ From b53eb93dd17c3d9d37397f4b60908479493820ef Mon Sep 17 00:00:00 2001 From: Darren Date: Fri, 5 Oct 2018 22:23:54 +0100 Subject: [PATCH 03/12] Example syntax update; Combine joined+time_joined claims --- extensions/extjwt.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index da0a52f2a..83240ec0e 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -40,7 +40,7 @@ Only one new command is introduced in this extension, `EXTJWT`. ### The EXTJWT Command -Syntax: `EXTJWT [channel]` +Syntax: `EXTJWT ( | * )` Response syntax: `EXTJWT [*] ` @@ -55,8 +55,7 @@ The client MAY send `EXTJWT` or `EXTJWT *` to the server to request a new JWT to The command MUST also support a single parameter of a channel name. Eg. `EXTJWT #channel`. The server MUST then reply with the channel name as its requested_target parameter, 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` 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. +* `joined` Number; Unix timestamp of the time in which the client the channel. 0 if not joined. * `modes` []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. @@ -102,10 +101,10 @@ Where the replied token is decoded into: #### A client logged into the IRC server and has channel operator privileges on a channel ~~~ [C -> S] EXTJWT #channel -[S -> C] EXTJWT #channel eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJ0ZXN0bmljayIsImFjY291bnQiOiJ0ZXN0bmljayIsIm5ldF9tb2RlcyI6W10sImNoYW5uZWwiOiIjY2hhbm5lbCIsImpvaW5lZCI6dHJ1ZSwidGltZV9qb2luZWQiOjE1Mjk5MTc1MDEsIm1vZGVzIjpbIm8iXX0.jd1VHnEN02mSw4g2BfB-gYOooktpua2HSd9qtcUBZ4M +[S -> C] EXTJWT #channel eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJ0ZXN0bmljayIsImFjY291bnQiOiJ0ZXN0bmljayIsIm5ldF9tb2RlcyI6W10sImNoYW5uZWwiOiIjY2hhbm5lbCIsImpvaW5lZCI6MTUyOTkxNzUwMSwibW9kZXMiOlsibyJdfQ.AKVHXXHoPFs8dOT2BfethA0ydKAjvGMjzL2vFcms-kc ~~~ Where the replied token is decoded into: ~~~json -{"exp":1529917513,"iss":"irc.example.org","nick":"testnick","account":"testnick","net_modes":[],"channel":"#channel","joined":true,"time_joined":1529917501,"modes":["o"]} +{"exp":1529917513,"iss":"irc.example.org","nick":"testnick","account":"testnick","net_modes":[],"channel":"#channel","joined":1529917501,"modes":["o"]} ~~~ From d1ad8d16518b2870a480662e23e9ba745dc7b434 Mon Sep 17 00:00:00 2001 From: Darren Date: Sat, 6 Oct 2018 13:52:16 +0100 Subject: [PATCH 04/12] Replacing the nick claim with the JWT standard sub (subject) claim --- extensions/extjwt.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index 83240ec0e..2d1e7bdf1 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -26,7 +26,7 @@ The IRC network creates the proof by generating signed JWT tokens and sending th The JWT token (https://jwt.io/) is an encoded JSON payload that is signed with a shared secret string between the IRC server and the external service. The JSON payload consists of known properties (claims) that include: * `exp` `1529917513` Expiry time for this token. Usually less than 1 minute from the token generation. * `iss` `"irc.example.org"` The server name that generated this token. -* `nick` `"somenick"` The nick of the user 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. * `net_modes` `["o"]` User modes the IRCd wishes to disclose. Eg, if the user an operator. @@ -48,7 +48,7 @@ The client MAY send `EXTJWT` or `EXTJWT *` to the server to request a new JWT to * `exp` Number; Unix timestamp for when this token expires. Usually less than 1 minute from the token generation. * `iss` String; The server name that generated this token. -* `nick` String; The nick of the client that requested 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. @@ -79,32 +79,32 @@ 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.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJzb21lbmljayIsImFjY291bnQiOiJzb21lbmljayIsIm5ldF9tb2RlcyI6WyJvIl19.NREHeoO-aewAry44erDgCHuVmUW9zyJjG05mJYCXXfs +[S -> C] EXTJWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InNvbWVuaWNrIiwiYWNjb3VudCI6InNvbWVuaWNrIiwibmV0X21vZGVzIjpbIm8iXX0.X_BOoVkpqkP8FoyF4bNFTiiGwBLBQtXjqCHYSEbu11w ~~~ Where the replied token is decoded into: ~~~json -{"exp":1529917513,"iss":"irc.example.org","nick":"somenick","account":"somenick","net_modes":["o"]} +{"exp":1529917513,"iss":"irc.example.org","sub":"somenick","account":"somenick","net_modes":["o"]} ~~~ #### A client connected to the IRC server without a registered account or operator privileges ~~~ [C -> S] EXTJWT * -[S -> C] EXTJWT * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJzb21lbmljayIsImFjY291bnQiOiIiLCJuZXRfbW9kZXMiOltdfQ.Vkm2XJXHz6rkq-R93fJUp88kNmAU9J65w46ZsQLjJrY +[S -> C] EXTJWT * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InNvbWVuaWNrIiwiYWNjb3VudCI6IiIsIm5ldF9tb2RlcyI6W119.X0-zcNzcBT_gSnPUOKk4Yawj2ncwDQ_0NwPYsDlWRwk ~~~ Where the replied token is decoded into: ~~~json -{"exp":1529917513,"iss":"irc.example.org","nick":"somenick","account":"","net_modes":[]} +{"exp":1529917513,"iss":"irc.example.org","sub":"somenick","account":"","net_modes":[]} ~~~ #### A client logged into the IRC server and has channel operator privileges on a channel ~~~ [C -> S] EXTJWT #channel -[S -> C] EXTJWT #channel eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJ0ZXN0bmljayIsImFjY291bnQiOiJ0ZXN0bmljayIsIm5ldF9tb2RlcyI6W10sImNoYW5uZWwiOiIjY2hhbm5lbCIsImpvaW5lZCI6MTUyOTkxNzUwMSwibW9kZXMiOlsibyJdfQ.AKVHXXHoPFs8dOT2BfethA0ydKAjvGMjzL2vFcms-kc +[S -> C] EXTJWT #channel eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InRlc3RuaWNrIiwiYWNjb3VudCI6InRlc3RuaWNrIiwibmV0X21vZGVzIjpbXSwiY2hhbm5lbCI6IiNjaGFubmVsIiwiam9pbmVkIjoxNTI5OTE3NTAxLCJtb2RlcyI6WyJvIl19.SDIfSUblfeA3k67ZQAX54xCuUZoCCv9RiMSjnvEmdro ~~~ Where the replied token is decoded into: ~~~json -{"exp":1529917513,"iss":"irc.example.org","nick":"testnick","account":"testnick","net_modes":[],"channel":"#channel","joined":1529917501,"modes":["o"]} +{"exp":1529917513,"iss":"irc.example.org","sub":"testnick","account":"testnick","net_modes":[],"channel":"#channel","joined":1529917501,"modes":["o"]} ~~~ From 51a288a312b3a135bb7615a9337a8cf2f0f4838b Mon Sep 17 00:00:00 2001 From: Darren Date: Sat, 6 Oct 2018 14:02:24 +0100 Subject: [PATCH 05/12] Versioning support --- extensions/extjwt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index 2d1e7bdf1..a1c38d9e5 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -34,7 +34,7 @@ When an external service is opened with this token in its URL, the external serv ## Usage -If the feature is available on the IRC server, the `EXTJWT` token is added to its ISUPPORT list. +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. Only one new command is introduced in this extension, `EXTJWT`. From 66c11e1a4d2d0105366c3d01283789d91f2d8d68 Mon Sep 17 00:00:00 2001 From: Darren Date: Sat, 6 Oct 2018 14:43:18 +0100 Subject: [PATCH 06/12] Notes on token expiration --- extensions/extjwt.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index a1c38d9e5..c159ec6e5 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -24,11 +24,11 @@ Once in use, this: The IRC network creates the proof by generating signed JWT tokens and sending 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 an encoded JSON payload that is signed with a shared secret string between the IRC server and the external service. The JSON payload consists of known properties (claims) that include: -* `exp` `1529917513` Expiry time for this token. Usually less than 1 minute from the token generation. +* `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. -* `net_modes` `["o"]` User modes the IRCd wishes to disclose. Eg, if the user an operator. +* `net_modes` `["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 using its pre-configured secret string and can then use the available claims to create any required user accounts and log the user in automatically. @@ -46,7 +46,7 @@ Response syntax: `EXTJWT [*] ` 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. +* `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. @@ -72,6 +72,12 @@ Eg: [S -> C] EXTJWT #channel gdG8gc2VuZCBvbiBvbmUgSVJDIDUxMiBjaGFyYWN0ZXIgbGluZSJ9.c9_pKy1jFsDeevja7o6spPa-JUyzg4z4k3A65fxwZWw ~~~ +#### 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. + +One minute 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". From 4a390fa0eea16d686cbb5142beb35714ba61a089 Mon Sep 17 00:00:00 2001 From: Darren Date: Sat, 11 Apr 2020 13:59:38 +0100 Subject: [PATCH 07/12] Optional verify URL; Optional service names; *modes claim renamed; --- extensions/extjwt.md | 76 ++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index c159ec6e5..e6d13d567 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -12,71 +12,82 @@ copyrights: 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 IRC network to offer proof that a user is connected with specific permissions and / or is joined to any channels, so that the external service can use this proof to authenticate users without any development ties between the IRC network and the external service such as using XMLRPC or custom bots or shared database access. +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) +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 proof works +### How the verification works -The IRC network creates the proof by generating signed JWT tokens and sending them to the client. The client may use this token to open an external service with the token in its URL. +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 an encoded JSON payload that is signed with a shared secret string between the IRC server and the external service. The JSON payload consists of known properties (claims) that include: +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. +* `vfy` `"https://irc.example.org/extjwtverify/?t=%s"` The URL that can verify this token. * `account` `"somenick"` The account name of the user that generated this token. Empty if not logged in. -* `net_modes` `["o"]` User modes the IRCd wishes to disclose. Eg, if the user is an operator. +* `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 using its pre-configured secret string and can then use the available claims to create any required user accounts and log the user in automatically. +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 shared secret for this IRC network, it can now verify the token directly. +2. The external service can make a HTTP GET request to the URL given in the `vfy` claim, 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 403 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. +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 ( | * )` +Syntax: `EXTJWT ( | * ) [service_name]` + +Response syntax: `EXTJWT [*] ` -Response syntax: `EXTJWT [*] ` +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 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: +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. -* `net_modes` []String; An array of user modes the IRCd may want to disclose. Eg, if the user is an operator. +* `umodes` []String; An array of user modes the IRCd may want to disclose. Eg, if the user is an operator. + +Optionaly, the JWT token MAY contain the following claim to provide the external service a way to verify the token: +* `vfy` String; A HTTP URL to verify the token. -The command MUST also support a single parameter of a channel name. Eg. `EXTJWT #channel`. The server MUST then reply with the channel name as its requested_target parameter, the JWT token containing the above claims and also the following claims relevant to the channel at that time: +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 in which the client the channel. 0 if not joined. -* `modes` []String; An array of the channel modes the client has in this channel. +* `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 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. +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.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJ0ZXN0bmljayIsImFjY291bnQiOiJ0ZXN0bmljayIsIm5ldF9tb2RlcyI6W10sImNoYW5uZWwiOiIjY2hhbm5lbCIsImpvaW5lZCI6dHJ1ZSwidGltZV9qb2luZWQiOjE1Mjk5MTc1MDEsIm1vZGVzIjpbIm8iXSwiY2xhaW0xIjoic29tZSBsb25nIHZhbHVlIiw -[S -> C] EXTJWT #channel * iY2xhaW0yIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW0zIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW00Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW01Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW02Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW03Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW04Ijoic29tZSBsb25nZXIgdmFsdWUgdG8gbWFrZSBzdXJlIHRoaXMgdG9rZW4gaXMgdG9vIGxvbmc -[S -> C] EXTJWT #channel gdG8gc2VuZCBvbiBvbmUgSVJDIDUxMiBjaGFyYWN0ZXIgbGluZSJ9.c9_pKy1jFsDeevja7o6spPa-JUyzg4z4k3A65fxwZWw +[S -> C] EXTJWT #channel * * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsIm5pY2siOiJ0ZXN0bmljayIsImFjY291bnQiOiJ0ZXN0bmljayIsInVtb2RlcyI6W10sImNoYW5uZWwiOiIjY2hhbm5lbCIsImpvaW5lZCI6MTUyOTkxNzUwMSwiY21v +[S -> C] EXTJWT #channel * * ZGVzIjpbIm8iXSwiY2xhaW0xIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW0yIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW0zIjoic29tZSBsb25nIHZhbHVlIiwiY2xhaW00Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW01Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW02Ijoic29tZ +[S -> C] EXTJWT #channel * SBsb25nIHZhbHVlIiwiY2xhaW03Ijoic29tZSBsb25nIHZhbHVlIiwiY2xhaW04Ijoic29tZSBsb25nZXIgdmFsdWUgdG8gbWFrZSBzdXJlIHRoaXMgdG9rZW4gaXMgdG9vIGxvbmcgdG8gc2VuZCBvbiBvbmUgSVJDIDUxMiBjaGFyYWN0ZXIgbGluZSJ9.wxRb7lH9OjENg_dTmPrDglBsN3Z17g1eEGJdp9Jsbqg ~~~ #### 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. -One minute 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. +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 @@ -85,32 +96,43 @@ 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.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InNvbWVuaWNrIiwiYWNjb3VudCI6InNvbWVuaWNrIiwibmV0X21vZGVzIjpbIm8iXX0.X_BOoVkpqkP8FoyF4bNFTiiGwBLBQtXjqCHYSEbu11w +[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","net_modes":["o"]} +{"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.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InNvbWVuaWNrIiwiYWNjb3VudCI6IiIsIm5ldF9tb2RlcyI6W119.X0-zcNzcBT_gSnPUOKk4Yawj2ncwDQ_0NwPYsDlWRwk +[S -> C] EXTJWT * * eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InNvbWVuaWNrIiwiYWNjb3VudCI6IiIsInVtb2RlcyI6W119.i_ak4qvb1BPdH0a0HyRNTz036rHE2lGrZ17SQV3LAFE ~~~ Where the replied token is decoded into: ~~~json -{"exp":1529917513,"iss":"irc.example.org","sub":"somenick","account":"","net_modes":[]} +{"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.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInN1YiI6InRlc3RuaWNrIiwiYWNjb3VudCI6InRlc3RuaWNrIiwibmV0X21vZGVzIjpbXSwiY2hhbm5lbCI6IiNjaGFubmVsIiwiam9pbmVkIjoxNTI5OTE3NTAxLCJtb2RlcyI6WyJvIl19.SDIfSUblfeA3k67ZQAX54xCuUZoCCv9RiMSjnvEmdro +[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"]} +~~~ + +#### A server responding with a verification (`vfy`) claim +~~~ +[C -> S] EXTJWT #channel forum.example.org +[S -> C] EXTJWT #channel forum.example.org eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInZmeSI6Imh0dHBzOi8vaXJjLmV4YW1wbGUub3JnL2V4dGp3dD90PSVzIiwic3ViIjoidGVzdG5pY2siLCJhY2NvdW50IjoidGVzdG5pY2siLCJ1bW9kZXMiOltdLCJjaGFubmVsIjoiI2NoYW5uZWwiLCJqb2luZWQiOjE1Mjk5MTc1MDEsImNtb2RlcyI6WyJvIl19.WhZpr-m2v2T6y1tlLFukX3pvk4k-tiQLzlW-poR74fk ~~~ Where the replied token is decoded into: ~~~json -{"exp":1529917513,"iss":"irc.example.org","sub":"testnick","account":"testnick","net_modes":[],"channel":"#channel","joined":1529917501,"modes":["o"]} +{"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"]} ~~~ From 6be574ee9e0b095709bf587951e790bcfbb72907 Mon Sep 17 00:00:00 2001 From: Darren Date: Sat, 11 Apr 2020 14:12:04 +0100 Subject: [PATCH 08/12] vfy 403 > 401 Co-Authored-By: Kyle Fuller --- extensions/extjwt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index e6d13d567..9f73d2535 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -33,7 +33,7 @@ The JWT token (https://jwt.io/) is a base64 encoded JSON payload that is signed 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 shared secret for this IRC network, it can now verify the token directly. -2. The external service can make a HTTP GET request to the URL given in the `vfy` claim, 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 403 status if the token is invalid. +2. The external service can make a HTTP GET request to the URL given in the `vfy` claim, 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. From 6ceab95822da40552ff1b2ced0fbc02338251af0 Mon Sep 17 00:00:00 2001 From: Darren Date: Wed, 15 Apr 2020 12:23:40 +0100 Subject: [PATCH 09/12] Update extensions/extjwt.md Co-Authored-By: Sadie Powell --- extensions/extjwt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index 9f73d2535..07f27c2ca 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -65,7 +65,7 @@ Optionaly, the JWT token MAY contain the following claim to provide the external 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 in which the client the channel. 0 if not joined. +* `joined` Number; Unix timestamp of the time at which the client joined the channel. 0 if not joined. * `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. From f3facfbe5f2686f2ab2a3322cadd31dacd3f5177 Mon Sep 17 00:00:00 2001 From: Darren Date: Mon, 20 Apr 2020 12:56:19 +0100 Subject: [PATCH 10/12] Channel `joined` claim to be 1 if no timestamp is available --- extensions/extjwt.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index 07f27c2ca..94d5b2246 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -65,7 +65,7 @@ Optionaly, the JWT token MAY contain the following claim to provide the external 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. +* `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. From f5a18794c8a08051af2860cea98866d6dd05bddb Mon Sep 17 00:00:00 2001 From: ItsOnlyBinary Date: Mon, 1 Jul 2024 15:07:43 +0100 Subject: [PATCH 11/12] Define possible errors --- extensions/extjwt.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index 94d5b2246..d402e0fcc 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -83,6 +83,18 @@ Eg: [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. From 7e0ce18526e654361d423b35185bfa1b10ccd46f Mon Sep 17 00:00:00 2001 From: ItsOnlyBinary Date: Mon, 1 Jul 2024 15:30:54 +0100 Subject: [PATCH 12/12] Remove vfy claim 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. --- extensions/extjwt.md | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/extensions/extjwt.md b/extensions/extjwt.md index d402e0fcc..1cd5fa628 100644 --- a/extensions/extjwt.md +++ b/extensions/extjwt.md @@ -27,13 +27,12 @@ The JWT token (https://jwt.io/) is a base64 encoded JSON payload that is signed * `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. -* `vfy` `"https://irc.example.org/extjwtverify/?t=%s"` The URL that can verify 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 shared secret for this IRC network, it can now verify the token directly. -2. The external service can make a HTTP GET request to the URL given in the `vfy` claim, 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. +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. @@ -59,8 +58,9 @@ The client will send at minimum `EXTJWT *` to the server to request a new JWT to * `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. -Optionaly, the JWT token MAY contain the following claim to provide the external service a way to verify the token: -* `vfy` String; A HTTP URL to verify the token. +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: @@ -137,14 +137,3 @@ 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"]} ~~~ - -#### A server responding with a verification (`vfy`) claim -~~~ -[C -> S] EXTJWT #channel forum.example.org -[S -> C] EXTJWT #channel forum.example.org eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Mjk5MTc1MTMsImlzcyI6ImlyYy5leGFtcGxlLm9yZyIsInZmeSI6Imh0dHBzOi8vaXJjLmV4YW1wbGUub3JnL2V4dGp3dD90PSVzIiwic3ViIjoidGVzdG5pY2siLCJhY2NvdW50IjoidGVzdG5pY2siLCJ1bW9kZXMiOltdLCJjaGFubmVsIjoiI2NoYW5uZWwiLCJqb2luZWQiOjE1Mjk5MTc1MDEsImNtb2RlcyI6WyJvIl19.WhZpr-m2v2T6y1tlLFukX3pvk4k-tiQLzlW-poR74fk -~~~ - -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"]} -~~~