Skip to content

Conversation

@kousu
Copy link

@kousu kousu commented May 31, 2025

FAST is a cookie-style authentication method that
lets clients store and auth with an unguesseable token. It enables clients to forget the user's full password, which is especially important for web-based clients, that are prone to data leaks. Leaked tokens can be invalidated.

Very messy, but I'm sharing for feedback.
Intended to fix conversejs/converse.js#3144

Some aside changes I needed for this:

  • I let handlers listen to the opening stanza
  • Set 'from' on the opening tag. (ref: https://github.com/xmppjs/xmpp.js/pull/1006/files#r1893267922)
  • Create a new handler type (I know, I know) that can search nested data. This made setting up listeners a lot more convenient.
  • Rearrange
  • During connection, replaced has_features with the direct XML element ?. liberally. That seems more direct and defensive.
  • Moved Status.AUTHENTICATING before FAST/SASL

I think the SASL negotiation logic can be cleaned up a lot, It could handle fallback through all the methods, instead of needing awkward special cases for FAST. Allowing handlers to hear the opening stanza means, I am pretty sure, all of SASL2 can become an event-driven plugin, and maybe all of SASL1.

Things that are bad:

  • too much copy-pasting
  • the SASL negotiation is brittle and only makes and tries one decision except for FAST which is bodged in awkwardly
  • saving/loading the FAST tokens is to be defined I coded something directly in here but really clients need to be making that decision (xmpp.js provided overridable methods to fill with localStorage or a cookie or something)
  • NSHandler was a whim of fancy. It should probably be backed out. Allowing searching for nested namespaces/tags (which most other xmpp libraries do?) tidies the code a lot, but I recognize it's offtopic, and there are more verbose ways to achieve FAST without them.
  • websocket checks for 'secure' before sending 'from', but bosh doesn't yet.
  • support the other HT- methods from the spec
  • pull SASL2 into sasl2.js and make it a plugin
  • load fast.js as a proper plugin instead of importing it in index.js. I did this for testing, so I wouldn't have to mess around too much with ConverseJS.
  • Needs to disentangle the circular dependencies between a plugin and code that needs to run during the early boot.
  • It doesn't support the invalidate=1option, and it's actually just fully impossible to log out (without digging around in the web debugger anyway)

kousu added a commit to kousu/converse.js that referenced this pull request May 31, 2025
kousu added a commit to kousu/converse.js that referenced this pull request May 31, 2025
@kousu
Copy link
Author

kousu commented May 31, 2025

Demo

demo1.mp4
demo2.mp4
demo3.mp4
demo4.mp4

Testing

Here's how I've been testing:

git clone -b sasl2_fast [email protected]:kousu/strophejs
git clone -b sasl2_fast [email protected]:kousu/converse.js
cd converse.js
npm ci
npm run serve & npm run watch & xdg-open https://localhost:8080/dev.html

On prosody, you need to enable the community repository and add these modules to your config:

	-- SASL2/FAST
		"sasl2";
		"sasl2_bind2";
		"sasl2_sm";
		"sasl2_fast";
		"client_management";

I also made heavy use of mod_stanza_debug but now that the basics are working that might be less necessary.

I haven't tested with ejabberd. And come to think of it I haven't tested with websockets or BOSH proxies either. But give it a shot and let me know what you think! And especially I could use some advice on code organization.

FAST is a cookie-style authentication method that
lets clients store and auth with an unguesseable token.
It enables clients to forget the user's full password,
which is especially important for web-based clients,
that are prone to data leaks. Leaked tokens can be
invalidated.

- https://xmpp.org/extensions/xep-0484.html
- https://xmpp.org/extensions/xep-0388.html

Very messy, but I'm sharing for feedback.
Intended to fix conversejs/converse.js#3144

Some aside changes I needed for this:
- I let handlers listen to the *opening* stanza
- Set 'from' on the opening <stream> tag. (ref: https://github.com/xmppjs/xmpp.js/pull/1006/files#r1893267922)
- Create a new handler type (I know, I know)
  that can search *nested data*. This made
  setting up listeners a lot more convenient.
- Rearrange
- During connection, replaced has_features with
  the direct XML element ?. liberally. That seems
  more direct and defensive.
- Moved Status.AUTHENTICATING before FAST/SASL

I think the SASL negotiation logic can be cleaned up a lot,
It could handle fallback through all the methods, instead
of needing awkward special cases for FAST. Allowing handlers
to hear the opening stanza means, I am pretty sure, all of
SASL2 can become an event-driven plugin, and maybe all of SASL1.

Things that are bad:
- too much copy-pasting
- the SASL negotiation is brittle and only tries one
  thing, except for FAST which is bodged in
- saving/loading the FAST tokens is to be defined
  I coded something directly in here but really
  clients need to be making that decision
  (xmpp.js provided overridable methods to fill
  with localStorage or a cookie or something)
- similarly, saving/loading the **user-agent ID**
  is left undefined. The tokens are pinned to
  each user agent, so you can't just pick one at
  connect, you have to cache it somewhere.
- NSHandler was a whim of fancy. It should probably be backed out.
  Allowing searching for *nested* namespaces/tags
  (which most other xmpp libraries do?) tidies the
  code a lot, but I recognize it's offtopic, and there
  are more verbose ways to achieve FAST without them.
- websocket checks for 'secure' before sending 'from', but bosh doesn't yet.
- support the other HT- methods from the spec
- pull SASL2 into sasl2.js and make it a plugin
- load fast.js as a proper plugin instead of importing
  it in index.js. I did this for testing, so I wouldn't
  have to mess around too much with ConverseJS.
- Needs to disentangle the circular dependencies
  between a plugin and code that needs to run during
  the early boot.
@kousu kousu mentioned this pull request Jun 9, 2025
9 tasks
@kousu
Copy link
Author

kousu commented Jun 9, 2025

Superseded by #840 :)

@kousu kousu closed this Jun 9, 2025
kousu added a commit to kousu/converse.js that referenced this pull request Jun 9, 2025
Also clean up FAST *and* SCRAM keys on log out;
otherwise, the credentials are still in the browser,
and could be stolen, or reused simply by someone
who knows to redefined conversejs-session-jid in localStorage.

Depends on strophe/strophejs#839

TODO:

* [ ] This *renames* reuse_scram_keys to reuse_keys to cover
      both FAST and SCRAM, so it should probably get a
      backwards-compatibility shim for the old name.
* [ ] Drop my development environment edit to package.json
      (without there's no way to test because both
      repos need to be in sync)
kousu added a commit to kousu/converse.js that referenced this pull request Jun 9, 2025
Also clean up FAST *and* SCRAM keys on log out;
otherwise, the credentials are still in the browser,
and could be stolen, or reused simply by someone
who knows to redefined conversejs-session-jid in localStorage.

Depends on strophe/strophejs#839

TODO:

* [ ] This *renames* reuse_scram_keys to reuse_keys to cover
      both FAST and SCRAM, so it should probably get a
      backwards-compatibility shim for the old name.
* [ ] Drop my development environment edit to package.json
      (without there's no way to test because both
      repos need to be in sync)
kousu added a commit to kousu/converse.js that referenced this pull request Jun 9, 2025
Also clean up FAST *and* SCRAM keys on log out;
otherwise, the credentials are still in the browser,
and could be stolen, or reused simply by someone
who knows to redefined conversejs-session-jid in localStorage.

Depends on strophe/strophejs#839

TODO:

* [ ] This *renames* reuse_scram_keys to reuse_keys to cover
      both FAST and SCRAM, so it should probably get a
      backwards-compatibility shim for the old name.
* [ ] Drop my development environment edit to package.json
      (without there's no way to test because both
      repos need to be in sync)
kousu added a commit to kousu/converse.js that referenced this pull request Jun 10, 2025
Also clean up FAST *and* SCRAM keys on log out;
otherwise, the credentials are still in the browser,
and could be stolen, or reused simply by someone
who knows to redefined conversejs-session-jid in localStorage.

Depends on strophe/strophejs#839

TODO:

* [ ] This *renames* reuse_scram_keys to reuse_keys to cover
      both FAST and SCRAM, so it should probably get a
      backwards-compatibility shim for the old name.
* [ ] Drop my development environment edit to package.json
      (without there's no way to test because both
      repos need to be in sync)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support XEP-0484: Fast Authentication Streamlining Tokens

1 participant