# Discourse Keybase Proof

**URL:** https://meta.discourse.org/t/discourse-keybase-proof/115239
**Category:** Feature
**Tags:** pr-welcome
**Created:** [April 16, 2019, 4:22pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239 "2019-04-16T16:22:48Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [April 16, 2019, 4:22pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/1 "2019-04-16T16:22:48Z")

</div>

We can implement the Keybase proof protocol, so people can add a proof of identity in the Discourse instances they participate.

> **[Keybase ♥'s Mastodon, and how to get your site on Keybase](https://keybase.io/blog/keybase-proofs-for-mastodon-and-everyone)**
>
> Official blog of Keybase

 ![image](https://global.discourse-cdn.com/meta/original/3X/0/f/0fab8bf546748fe2697227a4243bd58ea2b35ea2.jpeg)

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [April 17, 2019, 2:15am UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/2 "2019-04-17T02:15:16Z")

</div>

I really like the idea of spearheading an implementation here, I know it is a rather advanced feature that only a handful of people will use, but it is good to support this kind of protocol and should be easy to implement.

I am placing #pr-welcome on this, @codinghorror would you like this slotted on 2.4 or 2.5 or just play it by ear?

Note… I would like to first see a plugin implementing the protocol prior to pulling into core.

---

<div class="post-metadata">

### Author: ![codinghorror](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/codinghorror/32/110067_2.png) [@codinghorror](https://meta.discourse.org/u/codinghorror)
#### Post date: [April 17, 2019, 4:09am UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/3 "2019-04-17T04:09:22Z")

</div>

I think #pr-welcome is good to start with, I support this, but it’s not like paying customers are asking for it or anything..

---

<div class="post-metadata">

### Author: ![hellekin](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/hellekin/32/51636_2.png) [@hellekin](https://meta.discourse.org/u/hellekin)
#### Post date: [April 17, 2019, 12:25pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/4 "2019-04-17T12:25:29Z")

</div>

I suppose it could be implemented as a plugin, for starters.

---

<div class="post-metadata">

### Author: ![kb\_xgess](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/kb_xgess/32/148817_2.png) [@kb\_xgess](https://meta.discourse.org/u/kb_xgess)
#### Post date: [May 6, 2019, 5:50pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/5 "2019-05-06T17:50:02Z")

</div>

keybase employee here. we actually just started on a gem for implementing the proof protocol. once done, it should be pretty easy to make a discourse plugin from it.

---

<div class="post-metadata">

### Author: ![kb\_xgess](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/kb_xgess/32/148817_2.png) [@kb\_xgess](https://meta.discourse.org/u/kb_xgess)
#### Post date: [May 13, 2019, 8:47pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/6 "2019-05-13T20:47:24Z")

</div>

OK! Keybase gem for adding the open proof protocol to rails is here: [GitHub - keybase/prove\_keybase: ruby on rails gemified plugin for implementing our open proof protocol · GitHub](https://github.com/keybase/prove_keybase)

I poked a bit at the Discourse plugin system (very cool by the way), and I think someone who is familiar with it should have no trouble converting this gem. I’m available for any questions or help, and if you ping me (I’m on keybase `@xgess`) I can help get this turned on for a test or staging environment of yours with some fake accounts on our side.

---

<div class="post-metadata">

### Author: ![nealmcb](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/nealmcb/32/107350_2.png) [@nealmcb](https://meta.discourse.org/u/nealmcb)
#### Post date: [May 15, 2019, 5:47pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/7 "2019-05-15T17:47:49Z")

</div>

I note that there have been lots of conversations in this forum over at least the last 4 years showing a strong desire for encrypted communications in Discourse. And they usually end up noting that it is a really hard problem, especially when encrypted group chats are considered, and that integrating with Keybase is a recommended alternative for a variety of reasons.

So I would advise those who really do want convenient, robust, encrypted communications to support this integration work, which is far easier than the work already in process, and does provide group chats and much more, all reliably tied to users based on their Discourse persona.

Here are a few references, starting with a wise quote from co-founder [Sam Saffron](https://meta.discourse.org/u/sam)[sam](https://meta.discourse.org/u/sam)[co-founder](https://meta.discourse.org/g/team) about flaws with any web-based solution like Discourse:

> [@Encrypted PGP Messaging](https://meta.discourse.org/t/encrypted-pgp-messaging/19149/53):
>
> The underlying issue is that you can not trust the server if you want truly secure messaging between members. This means that the software used to encrypt and decrypt stuff should not be sent from the discourse server. I second what was said here, you want something like keybase or signal for secure comms, you have to invest in training here. Treat the info you have on Discourse as potentially leaked, there are just too many vectors. People hosting the service, web browser caches on local comp…

Note that Keybase solves this by having native clients for many platforms.

Next up, on the current [Discourse Encrypt project](https://meta.discourse.org/t/discourse-encrypt-rfc/107918/26)

> > Sam, would there be any way to extend this functionality to a category/threads (and allow by groups?)

> Absolutely not, this is not in scope and not planned even 3 iterations out.

Next, the [RFC for Discourse Encrypt](https://meta.discourse.org/t/encrypted-personal-messages/98765) which notes that they also don’t plan to properly address the multiple device or loss-of-key issues that Keybase is designed to get right:

> the UI clearly explains that if she forgets this secret she will **NEVER** have access to her encrypted messages anymore

So again, please note that Keybase is now easy to integrate with, and that it solves problems that other solutions aren’t even planning to address.

---

<div class="post-metadata">

### Author: ![DNSTARS](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/dnstars/32/100957_2.png) [@DNSTARS](https://meta.discourse.org/u/DNSTARS)
#### Post date: [May 15, 2019, 6:06pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/8 "2019-05-15T18:06:56Z")

</div>

Keybase integration into Discourse would be like Christmas for us.

---

<div class="post-metadata">

### Author: ![emanuele](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/emanuele/32/142687_2.png) [@emanuele](https://meta.discourse.org/u/emanuele)
#### Post date: [June 6, 2019, 10:11am UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/9 "2019-06-06T10:11:43Z")

</div>

I am writing a plugin to implement this 🙂 Since it’s my first attempt, I’d love some guidance.

This is what I am planning to do (feel free to suggest changes!):

1. I will implement it as a plugin (I already have a GitHub repo at `etamponi/discourse-keybase-proofs-plugin`, it’s empty for now since I didn’t push my experiments yet).

2. I think the only “full page” I need is the one for the prefill\_url endpoint (the one that will show the association between the Discourse and the Keybase user). I didn’t look at examples from other sites but I think that it should be pretty easy and simple. This page should only be visible if the Discourse user to be associated is the one that’s currently logged in. If no user is logged in, I’ll redirect to the login page, possibly with the username prefilled in the login overlay. If the wrong user is logged in, I’ll display an error message.

3. The plugin itself shouldn’t need any configuration option, since all the entries in the json configuration to be sent to Keybase can be computed from the Discourse settings.

4. I’ll use an outlet in the user profile page to show the keybase badge/current association status. With the same approach, I’ll also show a control to remove the association from the Discourse side. Additionally, as suggested in the Keybase doc, when a user visits their own profile page, I’ll make a liveness check for the association.

5. the rest of the endpoints will be JSON only.

Here are a couple questions:

1. Where should I store the associations? Should I create a DB migration, or should I use the PluginStore?

2. What would you suggest as the best way to present the user with the configuration to be sent to Keybase? I guess @kb_xgess might have some opinion on this!

Thanks in advance 🙂

---

<div class="post-metadata">

### Author: ![kb\_xgess](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/kb_xgess/32/148817_2.png) [@kb\_xgess](https://meta.discourse.org/u/kb_xgess)
#### Post date: [June 6, 2019, 3:19pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/10 "2019-06-06T15:19:44Z")

</div>

🔥 yes @emanuele. i’m happy to help. as for getting the config to keybase, i think the easiest for us is if each site hosts it at a stable path somewhere. that way all we need is the domain, and then we can fetch the config and turn it on from our side.

---

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [June 6, 2019, 3:36pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/11 "2019-06-06T15:36:57Z")

</div>

> [@emanuele](#):
>
> Additionally, as suggested in the Keybase doc, when a user visits their own profile page, I’ll make a liveness check for the association.

That may be better as a sidekiq background job for Discourse.

Like every 24h, you check up to 100 users who haven’t been updated in the last 30 days.

(All numbers subject to tweaking).

> [@emanuele](#):
>
> Where should I store the associations? Should I create a DB migration, or should I use the PluginStore?

I would go with a User custom field. Easy to get from a User object, and makes sense since association is per user.

---

<div class="post-metadata">

### Author: ![emanuele](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/emanuele/32/142687_2.png) [@emanuele](https://meta.discourse.org/u/emanuele)
#### Post date: [June 6, 2019, 3:42pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/12 "2019-06-06T15:42:25Z")

</div>

> [@Falco](#):
>
> I would go with a User custom field. Easy to get from a User object, and makes sense since association is per user.

Ok, I need to look at how to create a custom field 🙂 also, there can be more than one Keybase users linked to the same Discourse user (but not vice-versa), is a custom field still the best choice?

> [@Falco](#):
>
> That may be better as a sidekiq background job for Discourse.
> 
> Like every 24h, you check up to 100 users who haven’t been updated in the last 30 days.

I’ll need to investigate about this too 🙂

---

<div class="post-metadata">

### Author: ![Falco](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/falco/32/179432_2.png) [@Falco](https://meta.discourse.org/u/Falco)
#### Post date: [June 6, 2019, 3:47pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/13 "2019-06-06T15:47:25Z")

</div>

> [@emanuele](#):
>
> Ok, I need to look at how to create a custom field 🙂

Here are some examples: [discourse-signatures/plugin.rb at main · discourse/discourse-signatures · GitHub](https://github.com/discourse/discourse-signatures/blob/master/plugin.rb)

> [@emanuele](#):
>
> there can be more than one Keybase users linked to the same Discourse user (but not vice-versa), is a custom field still the best choice?

You can store a JSON, which can be an object with keys for each Keybase user, or one array, etc.

> [@emanuele](#):
>
> I’ll need to investigate about this too 🙂

Check [discourse-patreon/app/jobs/scheduled/patreon\_sync\_patrons\_to\_groups.rb at main · discourse/discourse-patreon · GitHub](https://github.com/discourse/discourse-patreon/blob/master/app/jobs/scheduled/patreon_sync_patrons_to_groups.rb)

---

<div class="post-metadata">

### Author: ![emanuele](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/emanuele/32/142687_2.png) [@emanuele](https://meta.discourse.org/u/emanuele)
#### Post date: [June 11, 2019, 10:52am UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/14 "2019-06-11T10:52:59Z")

</div>

I am making progress 🙂 The new-proof flow is _almost_ done, and the check flow should be quite easy to implement.

I am struggling to get the spec to run though. When I run `bundle exec rake 'plugin:spec[keybase-proofs]'`, this is what I get:

```plaintext
LOAD_PLUGINS=1 /Users/etamponi/.rbenv/versions/2.6.2/bin/ruby -S rspec ./plugins/keybase-proofs/spec/requests/proof_controller_spec.rb --profile

Randomized with seed 1279
F

Failures:

  1) KeybaseProofs::ProofController can create a proof
     Failure/Error: expect(response.status).to eq(500)

       expected: 500
            got: 404

       (compared using ==)
     # ./plugins/keybase-proofs/spec/requests/proof_controller_spec.rb:11:in `block (2 levels) in <top (required)>'

Top 1 slowest examples (33.58 seconds, 99.9% of total time):
  KeybaseProofs::ProofController can create a proof
    33.58 seconds ./plugins/keybase-proofs/spec/requests/proof_controller_spec.rb:8

Finished in 33.62 seconds (files took 3.68 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./plugins/keybase-proofs/spec/requests/proof_controller_spec.rb:8 # KeybaseProofs::ProofController can create a proof

```

It would be way better for me if I could do some TDD at this point, to get the routes well written without manually go through the browser flow.

The repository is: [GitHub - etamponi/discourse-keybase-proofs-plugin: Discourse Plugin for Keybase Proofs · GitHub](https://github.com/etamponi/discourse-keybase-proofs-plugin)

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [June 11, 2019, 12:12pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/15 "2019-06-11T12:12:29Z")

</div>

You’re using `fetch_user_from_parameters`

> <https://github.com/etamponi/discourse-keybase-proofs-plugin/blob/master/app/controllers/proof_controller.rb#L12>

which will raise a 404 if the user cannot be found

> <https://github.com/discourse/discourse/blob/cbd4d06da0f4686d9eb0fb4e070fcf96ff47f145/app/controllers/application_controller.rb#L479>

So you either need to add a `username` parameter to the request, or simply use `current_user` rather than relying on parameters.

---

<div class="post-metadata">

### Author: ![emanuele](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/emanuele/32/142687_2.png) [@emanuele](https://meta.discourse.org/u/emanuele)
#### Post date: [June 11, 2019, 1:23pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/16 "2019-06-11T13:23:34Z")

</div>

🤦‍♂️ 🤦‍♂️ 🤦‍♂️ Thanks for your hint! I had convinced myself that the 404 was coming from the router not seeing the plugin routes…

And also thanks for suggesting me to use `current_user` only, since I can make the “wrong user” check on the client side. Here in the backend, I would still need to validate the signature against KeyBase so it’s fine to not pass an `username` param, and the tests would be a bit easier to write too!

---

<div class="post-metadata">

### Author: ![kb\_xgess](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/kb_xgess/32/148817_2.png) [@kb\_xgess](https://meta.discourse.org/u/kb_xgess)
#### Post date: [June 14, 2019, 5:21pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/17 "2019-06-14T17:21:35Z")

</div>

this is exciting! let me know if i can help reviewing the code or setting up a test domain on keybase’s side with some users so you can verify that it all works. and just a reminder to check out a bunch of ruby code we recently wrote as a generic rails gem to implement this behavior: [GitHub - keybase/prove\_keybase: ruby on rails gemified plugin for implementing our open proof protocol · GitHub](https://github.com/keybase/prove_keybase). it handles a bunch of the weirder behavior you might not yet have encountered like (1) blocking attempts to prove a discourse account you don’t actually own, (2) sending the correct response codes when an existing user doesn’t have a proof vs that user not existing, …  
thanks for doing this!

---

<div class="post-metadata">

### Author: ![emanuele](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/emanuele/32/142687_2.png) [@emanuele](https://meta.discourse.org/u/emanuele)
#### Post date: [June 14, 2019, 5:24pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/18 "2019-06-14T17:24:34Z")

</div>

Thanks 🙂 I am reading through that plug-in extensively (and I’m using your implementation of KeybaseClient, almost unchanged 😛 ) I was just going to ask you if you could point me at what should be the behaviour when the proof is not valid. I skimmed through the error handling code but, perhaps because of my lack of expertise with Rails, I missed the response code you are mentioning

---

<div class="post-metadata">

### Author: ![kb\_xgess](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/kb_xgess/32/148817_2.png) [@kb\_xgess](https://meta.discourse.org/u/kb_xgess)
#### Post date: [June 14, 2019, 5:31pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/19 "2019-06-14T17:31:21Z")

</div>

sure thing. so a user starts from keybase and starts the proof creation flow. they get directed to discourse with the usernames and sig\_hash (token) already populated (discourse checks that the user is logged in with the correct account: `user_proving_own_account!`), they confirm and hit OK or submit or whatever. At that point, discourse checks again that it’s the correct user, and tries to save the proof. as part of that save, discourse needs to ask keybase if the proof is valid. i think this is what you’re talking about. if the proof isn’t valid (which could mean they mangled the initial URL or they have already revoked the signature in keybase), it’ll bubble up and hit `handle_proof_failed`, which is basically just a flash notice and a redirect.

does that answer your question??

---

<div class="post-metadata">

### Author: ![emanuele](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/emanuele/32/142687_2.png) [@emanuele](https://meta.discourse.org/u/emanuele)
#### Post date: [June 14, 2019, 5:37pm UTC](https://meta.discourse.org/t/discourse-keybase-proof/115239/20 "2019-06-14T17:37:42Z")

</div>

Ok, so I should just redirect back to the new\_proof\_url endpoint, fair enough 🙂

Another question. The server-side endpoint I wrote assumes that the logged-in user is the discourse user that is making the proof. Is this an error? I assumed this is ok because it would generate a “failed proof” error anyway, as the discourse username of the logged-in user and the username in the proof would not match.

Of course I am still doing the “user proving own account” part, but only on the client side, to show a nice message.

[Next page](https://meta.discourse.org/t/discourse-keybase-proof/115239.md?page=2)
