{"id":13632581,"url":"https://github.com/local-first-web/auth","last_synced_at":"2025-04-18T02:33:53.516Z","repository":{"id":42867956,"uuid":"258801810","full_name":"local-first-web/auth","owner":"local-first-web","description":"Decentralized authentication and authorization for team collaboration, using a secure chain of cryptological signatures. (Formerly known as 🌮 Taco.)","archived":false,"fork":false,"pushed_at":"2024-05-28T22:59:08.000Z","size":11726,"stargazers_count":185,"open_issues_count":24,"forks_count":16,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-05-29T13:38:03.536Z","etag":null,"topics":["authentication","authorization","cevitxe","cryptography","decentralized-applications","distributed-system","invitation","local-first","lockboxes","peer-to-peer","seitan","signature-chain","taco","team-collaboration"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/local-first-web.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-04-25T14:55:47.000Z","updated_at":"2024-05-31T15:39:41.868Z","dependencies_parsed_at":"2023-12-05T20:23:17.547Z","dependency_job_id":"f247cb54-80a7-48ce-8e4e-edb080099603","html_url":"https://github.com/local-first-web/auth","commit_stats":{"total_commits":296,"total_committers":2,"mean_commits":148.0,"dds":0.04391891891891897,"last_synced_commit":"1ea15f63513dda37419d53744ea1d8725a4adc54"},"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/local-first-web%2Fauth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/local-first-web%2Fauth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/local-first-web%2Fauth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/local-first-web%2Fauth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/local-first-web","download_url":"https://codeload.github.com/local-first-web/auth/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223772285,"owners_count":17199976,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","authorization","cevitxe","cryptography","decentralized-applications","distributed-system","invitation","local-first","lockboxes","peer-to-peer","seitan","signature-chain","taco","team-collaboration"],"created_at":"2024-08-01T22:03:07.616Z","updated_at":"2025-04-18T02:33:53.508Z","avatar_url":"https://github.com/local-first-web.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cimg src=\"https://raw.githubusercontent.com/local-first-web/branding/main/svg/auth-h.svg\"\nwidth=\"600\" alt=\"@localfirst/auth logo\" /\u003e\n\n`@localfirst/auth` is a TypeScript library providing **decentralized authentication and\nauthorization** for team collaboration, using a secure chain of cryptographic signatures.\n\n## Why\n\n🤝 You're building a [local-first](http://inkandswitch.com/local-first.html) app to enable\ndistributed collaboration [without a central\nserver](http://medium.com/all-the-things/a-web-application-with-no-web-server-61000a6aed8f).\n\n🔑 You want to **authenticate** users and manage their **permissions**.\n\n🚫 You **don't** want to depend on a centralized authentication server or a key management service.\n\n💙 You want to provide a **easy and seamless experience** to users creating and joining teams\n\n🤔 You **don't** want to expose any of the underlying cryptographic complexity.\n\n## How it works\n\nThis library uses a conflict-free replicated state container based on a **signature chain**\n(provided by the [CRDX](https://github.com/herbcaudill/crdx) library) to manage team membership, permissions, and authentication.\n\nAll changes to the team's membership and permissions are recorded on the signature chain as a\nsequence of **signed** and **hash-chained** actions.\n\n![](./docs/img/sigchain-med.png)\n\nEvery team member keeps a complete replica of the signature chain and can validate other members'\nactions independently. All **authorizations** can be traced back to the root action, created by the team's founding member. The chain\nthereby builds a **tamper-proof, distributed web of trust**.\n\nThe team's signature chain also acts as a self-contained certificate authority or **public key\ninfrastructure** (PKI) solution. At any point in time we calculate the team's current state from it,\nwhich includes each member's public keys, as well as their status and roles. This allows us to\nprovide **authenticated and encrypted peer-to-peer connections** between members.\n\n**Invitations** are handled using a [Seitan token\nexchange](https://book.keybase.io/docs/teams/seitan). Once admitted to the team, each member\ngenerates their own cryptographic keys for signatures and encryption. They also generate\n**device-level keys** that are stored in each devices' secure storage, and which never leave the\ndevice.\n\nWhen roles are changed, members leave, or devices are lost or replaced, keys are **rotated** and\nassociated data **re-encrypted**.\n\n👉 Learn more: [Internals](./docs/internals.md)\n\n## Demo\n\nThis repo includes a demo app. This will eventually simulate a simple group chat app, although the chat part hasn't been built yet; just the group membership parts.\n\n![](docs/img/demo.gif)\n\nTo run the app, clone the repo and run\n\n```bash\nyarn dev\n```\n\nThe app will be available at http://localhost:3000 .\n\nThis demo is also run by Cypress tests, which exercise most of the libary's functionality. To run these:\n\n```\nyarn dev:cy\n```\n\n## Usage\n\nThis library provides a `Team` class, which wraps the signature chain and encapsulates the team's\nmembers, devices, and roles. With this object, you can **invite new members** and **manage their\npermissions.**\n\nThis object can also use the public keys embedded in the signature chain, along with the user's own\nsecret keys, to provide **encryption** and **signature verification** within the team.\n\n#### Not included\n\n- **Storage** This library does **not** provide storage for user information (including keys) or the\n  signature chain.\n- **Networking** This library includes a protocol for synchronizing the team's signature chains, but\n  you need to provide a working socket connecting us to a peer. (The demo uses [@localfirst/relay](https://github.com/local-first-web/relay), which is a tiny relay server and client that bridges two WebSocket connections to allow peers to talk directly to each other.)\n\n### Examples\n\n```bash\nyarn add @localfirst/auth\n```\n\n#### Alice creates a new team\n\n```js\nimport { user, team } from '@localfirst/auth'\n\n// 👩🏾 Alice\nconst alice = user.create('alice')\nconst alicesTeam = team.create({ name: 'Spies Я Us', context: { user: alice } })\n```\n\nUsernames (`alice` in the example) identify a person uniquely within the team. You could use\nexisting user IDs or names, or email addresses.\n\n#### Alice invites Bob\n\n```js\n// 👩🏾 Alice\nconst { secretKey } = alicesTeam.invite('bob')\n```\n\nThe invitation key is a single-use secret that only Alice and Bob will ever know. By default, it is\na 16-character string like `aj7x d2jr 9c8f zrbs`, and to make it easier to retype if needed, it is\nin base-30 format, which omits easily confused characters. It might be typed directly into your\napplication, or appended to a URL that Bob can click to accept:\n\n\u003e Alice has invited you to team XYZ. To accept, click: http://xyz.org/accept/aj7x+d2jr+9c8f+zrbs\n\nAlice will send the invitation to Bob via a side channel she already trusts (phone call, email, SMS,\nWhatsApp, Telegram, etc).\n\n#### Bob accepts the invitation\n\nBob uses the secret invitation key to generate proof that he was invited, without divulging the key.\n\n```js\n// 👨🏻‍🦲 Bob\nimport { accept } from '@localfirst/auth'\nconst proofOfInvitation = accept('aj7x d2jr 9c8f zrbs')\n```\n\nWhen Bob shows up to join the team, anyone can validate his proof of invitation to admit him to the\nteam - it doesn't have to be an admin.\n\n```js\n// 👳🏽‍♂️ Charlie\nteam.admit(proofOfInvitation)\nconst success = team.has('bob') // TRUE\n```\n\n#### Alice defines a role and adds Bob\n\n```js\n// 👩🏾 Alice\nteam.addRole('managers')\nteam.addMemberRole('bob', 'managers')\n```\n\n#### Alice checks Bob's role membership\n\n```js\n// 👩🏾 Alice\nconst isAdmin = team.isAdmin('bob') // TRUE\n```\n\n#### Alice encrypts a message for managers\n\n```js\n// 👩🏾 Alice\nconst message = 'the condor flies at midnight'\nconst encrypted = team.encrypt(message, 'managers')\n```\n\n#### Bob decrypts the message\n\n```js\n// 👨🏻‍🦲 Bob\nconst decrypted = team.decrypt(encrypted) // 'the condor flies at midnight'\n```\n\n👉 Learn more: [API documentation](./docs/api.md).\n\n## Prior art\n\n💡 This project is inspired by and borrows heavily from Keybase: The signature chain is inspired by\n[their implementation for Keybase Teams](https://keybase.io/docs/team), and the invitation mechanism\nis based on their [Seitan token exchange specification](https://keybase.io/docs/teams/seitan_v2),\nproposed as a more secure alternative to TOFU, or _**T**rust **O**n **F**irst **U**se_.\n\n🌮 This library was originally called `taco-js`. TACO stands for _**T**rust **A**fter\n**C**onfirmation **O**f invitation_.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocal-first-web%2Fauth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flocal-first-web%2Fauth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flocal-first-web%2Fauth/lists"}