mirror of
https://github.com/moparisthebest/xeps
synced 2024-12-21 23:28:51 -05:00
1bd848f5f7
Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
490 lines
21 KiB
XML
490 lines
21 KiB
XML
<?xml version='1.0' encoding='UTF-8'?>
|
|
<!DOCTYPE xep SYSTEM 'xep.dtd' [
|
|
<!ENTITY % ents SYSTEM 'xep.ent'>
|
|
%ents;
|
|
]>
|
|
<?xml-stylesheet type='text/xsl' href='xep.xsl'?>
|
|
<xep>
|
|
<header>
|
|
<title>Easy User Onboarding</title>
|
|
<abstract>This document defines a protocol and URI scheme for user invitation in order to allow a third party to register on a server. The goal of this is to make onboarding for XMPP IM newcomers as easy as possible.</abstract>
|
|
&LEGALNOTICE;
|
|
<number>0401</number>
|
|
<status>Experimental</status>
|
|
<type>Standards Track</type>
|
|
<sig>Standards</sig>
|
|
<approver>Council</approver>
|
|
<dependencies>
|
|
<spec>XMPP Core</spec>
|
|
<spec>XEP-0001</spec>
|
|
<spec>XEP-0050</spec>
|
|
<spec>XEP-0082</spec>
|
|
<spec>XEP-0077</spec>
|
|
<spec>XEP-0147</spec>
|
|
<spec>XEP-0379</spec>
|
|
</dependencies>
|
|
<supersedes/>
|
|
<supersededby/>
|
|
<shortname>N/A</shortname>
|
|
<author>
|
|
<firstname>Marc</firstname>
|
|
<surname>Schink</surname>
|
|
</author>
|
|
<revision>
|
|
<version>0.2.0</version>
|
|
<date>2018-02-11</date>
|
|
<initials>ms</initials>
|
|
<remark>
|
|
<p>Used Data Forms for extension of In-Band Registration as required by <strong>XEP-0077</strong> § 4.</p>
|
|
<p>Added "defined condition" elements in error stanzas as required by <strong>RFC 6120</strong> § 8.3.2.</p>
|
|
<p>Changed type of "invalid-token" error to "modify".</p>
|
|
<p>Fix namespacing of Ad-Hoc commands</p>
|
|
<p>Bump namespace to invite:1</p>
|
|
</remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.1.0</version>
|
|
<date>2018-01-25</date>
|
|
<initials>XEP Editor (jwi)</initials>
|
|
<remark>Accepted by vote of Council on 2018-01-17.</remark>
|
|
</revision>
|
|
<revision>
|
|
<version>0.0.1</version>
|
|
<date>2018-01-10</date>
|
|
<initials>ms</initials>
|
|
<remark><p>First submission.</p></remark>
|
|
</revision>
|
|
</header>
|
|
<section1 topic='Introduction' anchor='intro'>
|
|
<p>Romeo is an active XMPP IM (Instant Messaging) user or the operator of
|
|
an XMPP server. He convinces Juliet (who may not have an XMPP account yet)
|
|
to install a client but she may still need to choose an XMPP server,
|
|
create an account, and add Romeo as a contact.
|
|
This specification defines two ways for Romeo to simplify this process for Juliet:</p>
|
|
<section2 topic='User Invitation'>
|
|
<p>If Romeo is an XMPP user, he can create an out-of-band link (URI)
|
|
which allows Juliet to:</p>
|
|
<ol>
|
|
<li>Download an XMPP client (if needed).</li>
|
|
<li>Optionally register an account with Romeo's server (if permitted by
|
|
the server rules), or with a public server.</li>
|
|
<li>Establish a mutual presence subscription between Romeo and Juliet.</li>
|
|
</ol>
|
|
<p>The process is designed to automatically skip steps that Juliet already
|
|
completed, to make the overall experience as smooth as possible.</p>
|
|
</section2>
|
|
<section2 topic='Account Creation'>
|
|
<p>If Romeo is an administrator of an XMPP server, he can create an
|
|
out-of-band link (URI) which allows Juliet to:</p>
|
|
<ol>
|
|
<li>Download an XMPP client (if needed).</li>
|
|
<li>Register an account on Romeo's server with a user name defined by
|
|
Romeo and a password not known to Romeo.</li>
|
|
<li>Establish a mutual presence subscription between Romeo and Juliet.</li>
|
|
</ol>
|
|
</section2>
|
|
</section1>
|
|
<section1 topic='Requirements' anchor='reqs'>
|
|
<p>This specification makes use of XMPP URIs. The basic URI scheme for XMPP
|
|
is defined in &rfc5122; and extended in &xep0147; and &xep0379;.
|
|
Furthermore, this heavily builds upon the blocks provided in
|
|
<cite>XEP-0379</cite> for landing page and roster subscription.
|
|
</p>
|
|
<p>
|
|
To create out-of-band invitation links, Romeo's server needs to implement
|
|
the &xep0050; commands specified in the following section, and his client
|
|
must be able to execute them.
|
|
</p>
|
|
<p>
|
|
Furthermore, Romeo's server SHOULD provide a HTTPS service hosting the
|
|
landing page.
|
|
</p>
|
|
</section1>
|
|
<section1 topic='Discovery' anchor='discover'>
|
|
<p>Romeo can query his server for the availability of "User Invitation" and
|
|
"Account Creation" commands:</p>
|
|
<example caption="Discover available ad-hoc commands"><![CDATA[
|
|
<iq type='get' from='romeo@example.com' to='example.com' id='disco'>
|
|
<query xmlns='http://jabber.org/protocol/disco#items'
|
|
node='http://jabber.org/protocol/commands'/>
|
|
</iq>
|
|
]]></example>
|
|
<p>TODO: use appropriate node namespace.</p>
|
|
<example caption="Discovery result for available ad-hoc commands"><![CDATA[
|
|
<iq type='result' to='romeo@example.com' from='example.com' id='disco'>
|
|
<query xmlns='http://jabber.org/protocol/disco#items'
|
|
node='http://jabber.org/protocol/commands'>
|
|
<item jid='example.com'
|
|
node='urn:xmpp:invite#invite'
|
|
name='Invite user'/>
|
|
<item jid='example.com'
|
|
node='urn:xmpp:invite#create-account'
|
|
name='Create account'/>
|
|
</query>
|
|
</iq>
|
|
]]></example>
|
|
<p>When performing the account creation, Juliet's client needs to ensure
|
|
that the server supports the extended IBR protocol with a <preauth>
|
|
token: TODO</p>
|
|
</section1>
|
|
<section1 topic='Glossary' anchor='glossary'>
|
|
<p>OPTIONAL.</p>
|
|
</section1>
|
|
<section1 topic='Use Cases' anchor='usecases'>
|
|
<section2 topic='Creating a User Invitation' anchor='create-invitation'>
|
|
<p>A user can execute the 'invite' command to obtain a new invitation link
|
|
with a unique invitation token.</p>
|
|
<example caption="Execute user invitation command"><![CDATA[
|
|
<iq type='set' from='romeo@example.com' to='example.com' id='exec1'>
|
|
<command xmlns='http://jabber.org/protocol/commands'
|
|
node='urn:xmpp:invite#invite'
|
|
action='execute'/>
|
|
</iq>
|
|
]]></example>
|
|
<example caption="User invitation finished"><![CDATA[
|
|
<iq type='result' to='romeo@example.com' from='example.com' id='exec2'>
|
|
<command xmlns='http://jabber.org/protocol/commands'
|
|
node='urn:xmpp:invite#invite'
|
|
status='completed'>
|
|
<x xmlns='jabber:x:data' type='result'>
|
|
<item>
|
|
<field var='uri'>
|
|
<value>xmpp:inviter@example.com?roster;preauth=TOKEN;ibr=y</value>
|
|
</field>
|
|
<field var='landing-url'>
|
|
<value>https://example.com/invite/#TOKEN</value>
|
|
</field>
|
|
<field var='expire'>
|
|
<value>2017-11-06T02:56:15Z</value>
|
|
</field>
|
|
</item>
|
|
</x>
|
|
</command>
|
|
</iq>
|
|
]]></example>
|
|
<p>The token should be unique, sufficiently
|
|
long and generated by a strong random number generator.</p>
|
|
<p>A server MUST provide the <strong>uri</strong> field which contains an
|
|
XMPP URI of the following format:</p>
|
|
<code>xmpp:inviter@example.com?roster;preauth=TOKEN;ibr=y</code>
|
|
<p>The <strong>ibr</strong> query component in the XMPP URI indicates that
|
|
the invitee is allowed to create an account on Romeo's server, using the
|
|
'preauth' token.
|
|
If the server does not support or allow in-band registration for invited
|
|
users, the server MUST omit the <strong>ibr</strong> query component.</p>
|
|
<p>Additionally, the server SHOULD provide the <strong>landing-url</strong>
|
|
field which contains an HTTPS URL of a web-based landing page as described
|
|
in &xep0379; § 3.3. The URL format may differ from the example shown here
|
|
depending on where the landing page is hosted.</p>
|
|
<p>If the server omits the <strong>landing-page</strong> field, Romeo's
|
|
client SHOULD generate an appropriate landing page URL hosted by the
|
|
client developer or a trusted third party.</p>
|
|
<p>A server MAY provide a field which provides the expiration date of the
|
|
generated token. The expiration date MUST conform to the DateTime profile
|
|
specified in &xep0082;. If the field is not provided, the token does not
|
|
expire.</p>
|
|
<p>Romeo's client should provide adequate means to export the
|
|
<strong>landing-page</strong> URL, possibly accompanied with a short
|
|
description and the <strong>expire</strong> information, so that Romeo can
|
|
share it with Juliet by other means than XMPP, like e-mail or a QR code.</p>
|
|
</section2>
|
|
<section2 topic='Landing Page' anchor='landing-page'>
|
|
<p>The landing page that the generated URL points to should correspond to
|
|
the format described in <cite>XEP-0379</cite> §3.3, and it needs to
|
|
convey the following information:</p>
|
|
<ul>
|
|
<li>A short text that this is an XMPP invitation from Romeo.</li>
|
|
<li>A client recommendation (based on the detected web browser/OS) with download links.</li>
|
|
<li>A prominent button that activates the encoded <strong>xmpp:</strong> link.</li>
|
|
</ul>
|
|
<p>If the landing page is hosted by Romeo's server, the server MAY display
|
|
additional information based on the supplied TOKEN value, like the name
|
|
of the inviter or validity information.</p>
|
|
</section2>
|
|
<section2 topic='Redeeming a User Invitation' anchor='redeem-invitation'>
|
|
<p>If Juliet does not have an XMPP client installed, she will not be able
|
|
to open the <strong>xmpp:</strong> link from the invitation page.
|
|
For this case, the landing page needs to indicate that a client must be
|
|
installed first, and that the link will not work as intended without.
|
|
The automatic installation of an appropriate IM client when a user
|
|
clicks on an <strong>xmpp:</strong> is outside of the scope of this
|
|
document.</p>
|
|
<p>With an XMPP client installed, Juliet can open the
|
|
<strong>xmpp:</strong> link and have the client process it
|
|
appropriately, as follows:</p>
|
|
<section3 topic='Pre-Configured Account' anchor='redeem-preconfigured'>
|
|
<p>If Juliet's client is already configured with an account, the default
|
|
action for the presented
|
|
<strong>xmpp:inviter@example.com?roster;...</strong> URI is to add the
|
|
inviter to Juliet's roster. This should be performed as described in
|
|
§3.4 of <cite>XEP-0379</cite>, by sending a presence subscription
|
|
request containing the 'preauth' token.</p>
|
|
<p>If Juliet already has Romeo in her roster, her client should open the
|
|
appropriate chat interface instead.</p>
|
|
</section3>
|
|
<section3 topic='No Configured Account' anchor='redeem-no-account'>
|
|
<p>If Juliet's client does not have an XMPP account configured, she
|
|
needs to login or register an account first. Therefore, the client
|
|
should provide an interface with the following options:</p>
|
|
<ul>
|
|
<li>Login with an existing XMPP account.</li>
|
|
<li>Register an account with Romeo's server (if the URI contains a
|
|
<strong>ibr=y</strong> parameter).</li>
|
|
<li>Register an account with a public or client-endorsed server.</li>
|
|
</ul>
|
|
<p>If the <strong>xmpp:</strong> URI provided by Romeo contains the
|
|
<strong>ibr=y</strong> parameter, it indicates that the server
|
|
supports the <link url="#preauth-ibr">Pre-Authenticated In-Band
|
|
Registration</link> defined in this document. If Juliet chooses this
|
|
approach, the server will ensure that after the registration, Romeo is
|
|
added to her roster with a full presence subscription.</p> <p>If
|
|
Juliet chooses to login or register with a different server, her
|
|
client must complete the respective process and issue a subscription
|
|
request as described in §3.4 of <cite>XEP-0379</cite>.</p>
|
|
</section3>
|
|
</section2>
|
|
<section2 topic='Initiating Account Creation' anchor='account-creation'>
|
|
<p>If Romeo is the administrator of an XMPP server, he might want to
|
|
ensure that Juliet obtains an account on this server, with a username
|
|
defined either by Romeo or by Juliet, and in a way that does not require
|
|
the out-of-band communication of user passwords.</p>
|
|
<p>TODO: description of overall process steps, design motivation.</p>
|
|
<example caption="Exceute account creation command"><![CDATA[
|
|
<iq type='set' from='romeo@example.com' to='example.com' id='exec1'>
|
|
<command xmlns='http://jabber.org/protocol/commands'
|
|
node='urn:xmpp:invite#create-account'
|
|
action='execute'/>
|
|
</iq>
|
|
]]></example>
|
|
<example caption="Service returns form for account creation"><![CDATA[
|
|
<iq type='result' to='romeo@example.com' from='example.com' id='exec1'>
|
|
<command xmlns='http://jabber.org/protocol/commands'
|
|
sessionid='config:20020923T213616Z-700'
|
|
node='urn:xmpp:invite#create-account'
|
|
status='executing'>
|
|
<actions execute='complete'>
|
|
<complete/>
|
|
</actions>
|
|
<x xmlns='jabber:x:data' type='form'>
|
|
<field var='username' label='Username' type='text-single'/>
|
|
<field var='roster-subscription' label='Roster subscription' type='boolean'/>
|
|
</x>
|
|
</command>
|
|
</iq>
|
|
]]></example>
|
|
<p>A server MAY require a username to be specified for account creation.
|
|
In this case, the server MUST add the <required/> element to the
|
|
username field.
|
|
The username MUST be a valid localpart as defined in &rfc6122; §2.3.</p>
|
|
<example caption="Account creation with specified username"><![CDATA[
|
|
<iq type='set' from='romeo@example.com' to='example.com' id='exec2'>
|
|
<command xmlns='http://jabber.org/protocol/commands'
|
|
sessionid='config:20020923T213616Z-700'
|
|
node='urn:xmpp:invite#create-account'>
|
|
<x xmlns='jabber:x:data' type='submit'>
|
|
<field var='username'>
|
|
<value>juliet</value>
|
|
</field>
|
|
</x>
|
|
</command>
|
|
</iq>
|
|
]]></example>
|
|
<example caption="Account creation finished"><![CDATA[
|
|
<iq type='result' to='romeo@example.com' from='example.com' id='exec2'>
|
|
<command xmlns='http://jabber.org/protocol/commands'
|
|
sessionid='config:20020923T213616Z-700'
|
|
node='urn:xmpp:invite#create-account'
|
|
status='completed'>
|
|
<x xmlns='jabber:x:data' type='result'>
|
|
<item>
|
|
<field var='uri'>
|
|
<value>xmpp:juliet@example.com?register;preauth=TOKEN</value>
|
|
</field>
|
|
<field var='landing-url'>
|
|
<value>https://example.com/invite/#TOKEN</value>
|
|
</field>
|
|
<field var='expire'>
|
|
<value>2017-11-06T02:56:15Z</value>
|
|
</field>
|
|
</item>
|
|
</x>
|
|
</command>
|
|
</iq>
|
|
]]></example>
|
|
<p>The server's response for account creation is the same as for user
|
|
invitation except for the format of the <strong>uri</strong> field which
|
|
contains an XMPP URI of the following format:</p>
|
|
<code>xmpp:juliet@example.com?register;preauth=TOKEN</code>
|
|
<p>If no username was specified during the account creation process, the
|
|
local part of the JID in the XMPP URI is omitted by the server which
|
|
results in the following format:</p>
|
|
<code>xmpp:example.com?register;preauth=TOKEN</code>
|
|
<p>TODO: note about sensitivity of TOKEN</p>
|
|
</section2>
|
|
<section2 topic='Pre-Authenticated In-Band Registration' anchor='preauth-ibr'>
|
|
<p>In order to allow invited users to register on a server, the
|
|
registration processs as defined in &xep0077; needs to be extended. The
|
|
invited user's client MUST add a <preauth> element in the 'TODO'
|
|
namespace to the 'jabber:iq:register' query in order to inform the
|
|
server that it wants to perform Pre-Authenticated IBR:</p>
|
|
<example caption="Retrieving registration fields"><![CDATA[
|
|
<iq type='get' id='reg1' to='example.com'>
|
|
<query xmlns='jabber:iq:register'>
|
|
<preauth xmlns='urn:xmpp:invite:1'/>
|
|
</query>
|
|
</iq>
|
|
]]></example>
|
|
<p>If the server supports and is ready to perform Pre-Authenticated IBR,
|
|
it MUST add a <token> element to the response (TODO: 'token' or
|
|
'preauth'?):</p>
|
|
<example caption="Receiving registration form"><![CDATA[
|
|
<iq type='result' to='romeo@example.com' from='example.com' id='reg1'>
|
|
<query xmlns='jabber:iq:register'>
|
|
<x xmlns='jabber:x:data' type='form'>
|
|
<field type='hidden' var='FORM_TYPE'>
|
|
<value>urn:xmpp:invite:1</value>
|
|
</field>
|
|
<field type='text-single' label='Username' var='username'>
|
|
<required/>
|
|
</field>
|
|
<field type='text-private' label='Password' var='password'>
|
|
<required/>
|
|
</field>
|
|
<field type='text-single' label='Invite token' var='token'>
|
|
<required/>
|
|
</field>
|
|
</x>
|
|
</query>
|
|
</iq>
|
|
]]></example>
|
|
<example caption='Receiving registration form with error (invalid token)'><![CDATA[
|
|
<iq type='error' from='example.com' id='reg1'>
|
|
<query xmlns='jabber:iq:register'>
|
|
<x xmlns='jabber:x:data' type='form'>
|
|
<field type='hidden' var='FORM_TYPE'>
|
|
<value>urn:xmpp:invite:1</value>
|
|
</field>
|
|
<field type='text-single' var='username'>
|
|
<value>juliet<value/>
|
|
</field>
|
|
<field type='text-private' var='password'>
|
|
<value>m1cro$oft<value/>
|
|
</field>
|
|
<field type='text-single' var='token'>
|
|
<value>BADTOKEN<value/>
|
|
</field>
|
|
</x>
|
|
</query>
|
|
<error type='modify'>
|
|
<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
|
|
<invalid-token xmlns='urn:xmpp:invite:1'/>
|
|
</error>
|
|
</iq>
|
|
]]></example>
|
|
<example caption='Receiving registration form with error (token expired)'><![CDATA[
|
|
<iq type='error' from='example.com' id='reg1'>
|
|
<query xmlns='jabber:iq:register'>
|
|
<x xmlns='jabber:x:data' type='form'>
|
|
<field type='hidden' var='FORM_TYPE'>
|
|
<value>urn:xmpp:invite:1</value>
|
|
</field>
|
|
<field type='text-single' var='username'>
|
|
<value>juliet<value/>
|
|
</field>
|
|
<field type='text-private' var='password'>
|
|
<value>m1cro$oft<value/>
|
|
</field>
|
|
<field type='text-single' var='token'>
|
|
<value>OLDTOKEN<value/>
|
|
</field>
|
|
</x>
|
|
</query>
|
|
<error type='cancel'>
|
|
<not-allowed xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
|
|
<token-expired xmlns='urn:xmpp:invite:1'/>
|
|
</error>
|
|
</iq>
|
|
]]></example>
|
|
<p>After the invitee has successfully registered on the inviter's server
|
|
and roster subscription is enabled for account creation, the server MUST
|
|
use roster pushes as defined in &rfc6121; §2.1.6 in order to inform the
|
|
inviter about the invitee's new account without the need to reconnect.</p>
|
|
<example caption="Push roster item of invitee to inviter"><![CDATA[
|
|
<iq type='set' from='romeo@example.com' id='push'>
|
|
<query xmlns='jabber:iq:roster'>
|
|
<item subscription='both' jid='juliet@example.com'/>
|
|
</query>
|
|
</iq>
|
|
]]></example>
|
|
</section2>
|
|
</section1>
|
|
<section1 topic='Business Rules' anchor='rules'>
|
|
<section2 topic='Fallback to Client-Side PARS'>
|
|
<p>If the inviter's server does not support user invitation, the client
|
|
application SHOULD silently fall back to &xep0379; for a good user
|
|
experience.</p>
|
|
</section2>
|
|
<section2 topic='Account Creation'>
|
|
<p>If a username was specified during the account creation process, the
|
|
server SHOULD NOT create an account on the server until the invitee
|
|
actually registers it with the corresponding token.
|
|
The server MUST reserve the username at least until the corresponding
|
|
token expires.</p>
|
|
</section2>
|
|
</section1>
|
|
<section1 topic='Implementation Notes' anchor='impl'>
|
|
<section2 topic='XMPP Server Suggestion for Invitees'>
|
|
<p>If the invitee opens an invitation URI with <strong>ibr=y</strong> and
|
|
chooses to create a new account, the client SHOULD pre-fill the
|
|
inviter JID's domain part as the new account's domain. The client MAY
|
|
provide a mechanism to enter or choose a different server, though.</p>
|
|
</section2>
|
|
</section1>
|
|
<section1 topic='Accessibility Considerations' anchor='access'>
|
|
<p>OPTIONAL.</p>
|
|
</section1>
|
|
<section1 topic='Internationalization Considerations' anchor='i18n'>
|
|
<p>OPTIONAL.</p>
|
|
</section1>
|
|
<section1 topic='Security Considerations' anchor='security'>
|
|
<p>See security considerations in &xep0379;.</p>
|
|
</section1>
|
|
<section1 topic='IANA Considerations' anchor='iana'>
|
|
<p>This document requires no interaction with &IANA;.</p>
|
|
</section1>
|
|
<section1 topic='XMPP Registrar Considerations' anchor='registrar'>
|
|
<p>As authorized by &xep0147;, the XMPP Registrar maintains a registry of
|
|
queries and key-value pairs for use in XMPP URIs (see &QUERYTYPES;).</p>
|
|
<p>The key-value parameter <strong>preauth</strong> is added to the
|
|
<strong>register</strong> query action as defined in &xep0077;</p>
|
|
<code><![CDATA[
|
|
<querytype>
|
|
<name>register</name>
|
|
...
|
|
<key>
|
|
<name>preauth</name>
|
|
<desc>the token used to allow one-time in-band registration on the inviter's server</desc>
|
|
</key>
|
|
</querytype>
|
|
]]></code>
|
|
|
|
<p>In addition to the <strong>preauth</strong> key-value parameter define
|
|
in &xep0379;, the <strong>ibr</strong> parameter is added to the
|
|
<strong>roster</strong> query action.</p>
|
|
<code><![CDATA[
|
|
<querytype>
|
|
<name>roster</name>
|
|
...
|
|
<key>
|
|
<name>ibr</name>
|
|
<value>y</value>
|
|
<desc>the parameter to indicate that the token allows the invitee to create an account on the inviter's server via in-band registration</desc>
|
|
</key>
|
|
</querytype>
|
|
]]></code>
|
|
</section1>
|
|
<section1 topic='XML Schema' anchor='schema'>
|
|
<p>REQUIRED for protocol specifications.</p>
|
|
</section1>
|
|
</xep>
|