Julia (named for early labor leader Julia O'Connor) is a lightweight implementation of the Sessionless authentication protocol, which allows implementers to associate keys with a user creating a sort of switchboard for Sessionless keys.
Julia is composed of a CRUD server and database pair, and companion client-side libraries. This repo defines the contract between client and server via REST API, provides database implementation(s) for storing the models used in that contract, and the methods necessary in a client implementation.
The typical usage will look something like:
sequenceDiagram
Client->>+Server: Register User
Server->>+DB: Save userUUID
Server->>+Client: Sends userUUID
SecondClient->>+Server: Sends pubKey of second client to associate
Client->>+Server: Verifies that second client should be associated
Server->>+DB: Associates pubKey to user's uuid
SecondClient->>+Server: Second client sends message for first client
Server->>+DB: Checks if SecondClient is associated with first client
Server->>+Client: Sends message on to first client
And here's what the architecture looks like:
flowchart TD
A[(DB)] <-->|CRUD| B{Server}
B <--> |REST API| C[SDK in Language 1]
B <-->|REST API| D[SDK in Language 2]
B <-->|REST API| E[SDK in Language 3]
It doesn't get much CRUDier than this API:
PUT
/user/create
Creates a new user if pubKey does not exist, and returns existing uuid if it does.
name required data type description pubKey true string (hex) the publicKey of the user's keypair timestamp true string in a production system timestamps narrow window for replay attacks signature true string (signature) the signature from sessionless for the message
http code content-type response 200
application/json
{"userUUID": <uuid>}
400
application/json
{"code":"400","message":"Bad Request"}
curl -X PUT -H "Content-Type: application/json" -d '{"pubKey": "key", "timestamp": "now", "signature": "sig"}' https://www.juliaswitch.com/user/create
GET
/user/:uuid?timestamp=&signature=
Returns a user's associated keys
name required data type description timestamp true string in a production system timestamps prevent replay attacks signature true string (signature) the signature from sessionless for the message
http code content-type response 200
application/json
{"keys": {"interactingKeys": [{"userUUID": <uuid>, "pubKey": <pubKey>}], "coordinatingKeys": []}
406
application/json
{"code":"406","message":"Not acceptable"}
curl -X GET -H "Content-Type: application/json" https://www.juliaswitch.com/<uuid>?timestamp=123&signature=signature
POST
/user/:uuid/associate/prompt
Creates an association prompt
name required data type description timestamp true string in a production system timestamps prevent replay attacks signature true string (signature) the signature from sessionless for the message
http code content-type response 200
application/json
{prompt: <prompt>}
400
application/json
{"code":"400","message":"Bad Request"}
curl -X POST -H "Content-Type: application/json" -d '{"timestamp": "right now", "newUUID": <uuid>, "newPubKey": <new pubKey>, "signature": "signature", "newSignature": <new signature>}' https://www.juliaswitch.com/user/<uuid>/associate
POST
/user/:uuid/associate
Associates two users so they can message
name required data type description timestamp true string in a production system timestamps prevent replay attacks newUUID true string the uuid to associate newPubKey true string the pubKey to associate prompt true string the prompt for the association signature true string (signature) the signature from sessionless for the message newSignature true string (signature) the signature from sessionless for the new key message
http code content-type response 200
application/json
{ user }
400
application/json
{"code":"400","message":"Bad Request"}
curl -X POST -H "Content-Type: application/json" -d '{"timestamp": "right now", "newUUID": <uuid>, "newPubKey": <new pubKey>, "prompt": <prompt>, "signature": "signature", "newSignature": <new signature>}' https://www.juliaswitch.com/user/<uuid>/associate
DELETE
/associated/:associatedUUID/user/:uuid
Deletes a pubKey from the user
name required data type description timestamp true string in a production system timestamps prevent replay attacks signature true string the signature
http code content-type response 200
application/json
{"deleted": true}
400
application/json
{"code":"400","message":"Bad Request"}
curl -X DELETE https://www.juliaswitch.com/associated/<associated uuid>/user/<uuid>
DELETE
/user/:uuid
Deletes a uuid and pubKey
name required data type description timestamp true string in a production system timestamps prevent replay attacks signature true string the signature
http code content-type response 200
application/json
{"deleted": true}
400
application/json
{"code":"400","message":"Bad Request"}
curl -X DELETE https://www.juliaswitch.com/<uuid>
POST
/recover
Initiates a recovery flow for a user. This works like associating a user in reverse.
name required data type description timestamp true string in a production system timestamps prevent replay attacks newUUID true string the uuid to associate newPubKey true string the pubKey to associate signature true string (signature) the signature from sessionless for the message newSignature true string (signature) the signature from sessionless for the new key message
http code content-type response 200
application/json
{keys: [...keys]}
400
application/json
{"code":"400","message":"Bad Request"}
curl -X POST -H "Content-Type: application/json" -d '{"timestamp": "right now", "newUUID": <uuid>, "newPubKey": <new pubKey>, "signature": "signature", "newSignature": <new signature>}' https://www.juliaswitch.com/recover
POST
/message
Posts a message
name required data type description timestamp true string in a production system timestamps narrow the risk of replay attacks senderUUID true string the sender's uuid receiverUUID true string the receiver's uuid content true string the content to post signature true string (signature) the signature from sessionless for the message
http code content-type response 200
application/json
{success: true}
400
application/json
{"code":"400","message":"Bad Request"}
curl -X POST -H "Content-Type: application/json" -d '{"timestamp": "right now", "senderUUID": <uuid>, "receiverUUID": <uuid>, "message": <message>, "signature": "signature"}' https://www.juliaswitch.com/message
GET
/messages/user/:uuid?timestamp=&signature=
Returns a user's associated keys
name required data type description timestamp true string in a production system timestamps narrows the risk of replay attacks uuid true string the user's uuid signature true string (signature) the signature from sessionless for the message
http code content-type response 200
application/json
{"keys": [{"userUUID": <uuid>, "pubKey": <pubKey>}]
406
application/json
{"code":"406","message":"Not acceptable"}
curl -X GET -H "Content-Type: application/json" https://www.juliaswitch.com/messages?uuid=<uuid>timestamp=123&signature=signature
One of the biggest benefits of Sessionless is that it doesn't need to store any sensitive data. This means all of the data Julia cares about can all be saved in a single table/collection/whatever-other-construct-some-database-may-have. And that table looks like:
uuid | pubKey | keys |
---|---|---|
string | string | {uuid, key}[] |
And for messages it looks like:
uuid | timestamp | content |
---|---|---|
string | string | string |
uuid, and pubKey should have unique constraints (Sessionless generated keys and uuids should not collide, but since this is a public API people may just reuse keys and uuids).
Client SDKs need to generate keys via Sessionless, and implement the networking to interface with the server. To do so they should implement the following methods:
createUser(saveKeys, getKeys, [optionalUser])
- Should generate keys, save them appropriately client side, and PUT to /user/create.
getUser(uuid)
- Gets a user
getPrompt(uuid)
- Gets a one-time use code for associating keys
signPrompt(uuid, prompt)
- Posts a signed prompt
associate(uuid, signedPrompt)
- associates two keys
deleteKey(uuid, associatedUUID)
- Deletes an associated key
postMessage(uuid, receiverUUID, contents)
- Posts a message
getMessages(uuid)
- Gets a user's messages
deleteUser(uuid)
- Should DELETE a user by calling /user/:uuid.
NOTE Julia is experimental, and the instance at juliaswitch.com is ephemeral, and may go away or reset at any time. If you're making the next WhatsApp and want to use juliaswitch, you're advised to self-host it, or contact zach@planetnine.app to help him upgrade the micro instance it runs on :).
-
Any time you have a need for friends, contacts, or users associating, you can use Julia
-
Any sort of messaging you want to do see Julia messenger
-
You can use continuebee for account continuity before using more intrusive auth layers. I.e. instead of having potential players bounce off because of needing to enter their email/password before playing, you can auth with continuebee, and then ask for email/password when they hit level five after they've been hooked.
-
Just use it as a practice backend before figuring out all the auth needs of your game/app.
This is a bit dependent on what the server implementations are, so we'll fill the details in later, but the idea is that continuebee is hostable by others either for public use like the main instance, or private use.
To add to this repo, feel free to make a [pull request][pr].