diff --git a/README.md b/README.md
index e6570d998475b1ad7c083be3036dd03ffd3fd336..7b929d1854d6e58f9be91d69af52d80362891633 100644
--- a/README.md
+++ b/README.md
@@ -236,26 +236,7 @@ Miami           25.77   -80.19
 Montreal        45.52   -73.65
 ```
 
-## Bucket token auth
+## invite system - bucket token auth with invitectl
 
-Resources (bridges and gateways) can be given a "bucket" property to denote that they should be restricted/not part of publicly available assets.
+Resources (bridges and gateways) can be given a "bucket" property to denote that they should be restricted/not part of publicly available assets. Admins can then generate auth tokens which would give end users access to those resources. The cli tool `invitectl` docs can be found [here](/cmd/invitectl).
 
-Admins can then generate auth tokens which would give end users access to those resources.
-
-You can use the accompanying CLI to generate said tokens:
-```
-❯ go run ./cmd/tokens --buckets "bucket1,bucket2" --number-tokens 10
-Tokens:
-solitech_z6tV8f+1jpYMBgmE0J6jZQ==
-solitech_bYnFp+YzPTp/71/edSDEiw==
-solitech_pusRycrUBH9lxvkVcbIyXQ==
-solitech_e9JckBd9QzYmSE4wo2jQBQ==
-solitech_564x5U+rANCS1jbpvIeQvA==
-solitech_zNcbJeFyMANj0kIxGruIpw==
-solitech_t3/B7mdKB2tPbcnNdIejpw==
-solitech_tLdCZT0QVPyPuNJFdlpvvQ==
-solitech_G5ACBRpwqcivbMEkC708OA==
-solitech_u6Zoe3ftUcVmLb3lm/KsSw==
-```
-
-These tokens can then be passed in as a `x-menshen-auth-token` header when making requests to menshen which will allow that request access to private resources in "bucket1" and "bucket2".
diff --git a/cmd/invitectl/README.md b/cmd/invitectl/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f9999859e9b0fbf5d67b5088c54a0125c63f8115
--- /dev/null
+++ b/cmd/invitectl/README.md
@@ -0,0 +1,121 @@
+# invitectl - cli to manage invite tokens
+
+The tool allows you to create new invite tokens, that can be shared to a community. Invite tokens are stored in a sqlite database. Please run these  commands in the menshen container. It needs to modify the database menshen is using. If the db does not exist, it is generated.
+
+## Build instructions
+
+```
+clone this repo
+cd cmd/invitectl
+go build .
+invitectl ./invitectl -h
+A simple cli tool to manage invite tokens for LEAP VPN
+
+Usage:
+  invitectl [command]
+
+Available Commands:
+  completion  Generate the autocompletion script for the specified shell
+  delete      Delete Invite Tokens in db by bucket(s) or by key
+  delete-all  Delete all invite tokens in database
+  help        Help about any command
+  list        List all invite tokens stored in database
+  new         Add new invite token to database
+
+Flags:
+      --db string   Path to sqlite database. Creates a new db if file does not exist (required)
+  -h, --help        help for invitectl
+
+Use "invitectl [command] --help" for more information about a command.
+```
+
+## First, let's create a new invite token
+
+```
+./invitectl new -h
+Add new invite token to database
+
+Usage:
+  invitectl new [flags]
+
+Flags:
+  -b, --buckets string                 Comma separated list of buckets
+  -d, --debug                          Enable debug logging
+  -h, --help                           help for new
+  -c, --invite-code-parameter string   Yaml file with invite code parameters to print the whole invite code
+  -l, --key-length int                 Number of random bytes for a generated invite token (default 16)
+  -n, --number int                     Number of invite tokens to create (default 1)
+  -p, --prefix string                  Static prefix used for all generated invite tokens (default "solitech_")
+
+Global Flags:
+      --db string   Path to sqlite database. Creates a new db if file does not exist (required)
+```
+
+The database can be specified for all commands by the environment variable `DB=invites.db`. As invite tokens are stored as hashes (`sha2`), they can only printed in a shareable way when they are generated. Therefore, the information for the whole invite code needs to be specified in a yaml config file:
+
+```bash
+pea@peabox: ./invitectl --db invites.db new --buckets bucket1,bucket2 --invite-code-parameter parameters.yml --debug
+   • Please keep in mind that invite tokens are saved as hash and can only printed once!
+   • SHA265 hashed and base64 encoded Invite Token (saved in db): z5OmQgeCsm9TVtSvL+NGflT+kfd1eILvVcT1xrH5FFg=
+   • Generated invite token solitech_y8wh4sIrbUWaEaZ/fJNNQw== for buckets "bucket1,bucket2"
+   • Invite code: obfsvpnintro://localhost:4430/?cert=TQttsNdxY7TNiJUUZne8JYoVvOEjaEg5LaHis9V9sSNPNSxqChF2WuT19yLIM659un2%2BWQ&fqdn=localhost&kcp=1&auth=solitech_y8wh4sIrbUWaEaZ%2FfJNNQw%3D%3D
+   • Successfully inserted invite token to database
+```
+
+This is the content of `parameters.yml`:
+
+```yaml
+type: obfsvpnintro
+addr: localhost:4430
+cert: TQttsNdxY7TNiJUUZne8JYoVvOEjaEg5LaHis9V9sSNPNSxqChF2WuT19yLIM659un2+WQ
+fqdn: localhost
+kcp: true
+```
+
+An invite code belongs to one or more bucket. A (private) gateway/bridge belongs to one or more bucket. This assignment is stored in the inventory and not in the db.  You can generate multiple invite tokens with `--number`. Your invite token can have a prefix (`solitech_` in this case).
+
+## List all invite tokens
+
+```pea@peabox:invitectl ./invitectl --db invites.db list             
+pea@peabox: ./invitectl --db invites.db list             
+   •                                        invite token (hashed) buckets
+   •                 45wKtavTLOWVL8thlyvqq/pMuqCETDmWX5HwNkVWE5w= bucket1 bucket2
+   •                 z5OmQgeCsm9TVtSvL+NGflT+kfd1eILvVcT1xrH5FFg= bucket1 bucket2
+   •                 1LaYPMpEh7tw74D0jgs/iuypuhV93IIYVAA8CiEDMNM= bucket1 bucket3
+   •                 Z8YRjdz1Q0mZs3POsbRoNBoLIzz2vxiUAZzXiWGkTBc= bucket2
+   •                 FCQKTaYe3Z0tuJS7wFC77FRdXshRu/hhHXC9N032Hxg= bucket2
+   •                 pYFxB4OlPvLhNhxloGqiOAfOO96eJQhKI+m1pho4hJU= bucket2	
+```
+
+## Delete by buckets
+
+```
+pea@peabox: ./invitectl --db invites.db delete --bucket bucket2
+   • Successfully deleted 5 invite token(s) with bucket "bucket2"
+pea@peabox: ./invitectl --db invites.db list                   
+   •                                        invite token (hashed) buckets
+   •                 1LaYPMpEh7tw74D0jgs/iuypuhV93IIYVAA8CiEDMNM= bucket1 bucket3
+```
+
+## Delete by invite token
+
+```
+pea@peabox: ./invitectl --db invites.db new --buckets bucket4 --invite-code-parameter parameters.yml 
+   • Please keep in mind that invite tokens are saved as hash and can only printed once!
+   • Generated invite token solitech_UjxcL3ROgF/2wBV44jFOuQ== for buckets "bucket4"
+   • Invite code: obfsvpnintro://localhost:4430/?cert=TQttsNdxY7TNiJUUZne8JYoVvOEjaEg5LaHis9V9sSNPNSxqChF2WuT19yLIM659un2%2BWQ&fqdn=localhost&kcp=1&auth=solitech_UjxcL3ROgF%2F2wBV44jFOuQ%3D%3D
+
+pea@peabox: ./invitectl --db invites.db delete --token -       
+Enter invite token: solitech_UjxcL3ROgF/2wBV44jFOuQ==
+   • Successfully deleted 1 invite token(s) with token "solitech_UjxcL3ROgF/2wBV44jFOuQ=="
+```
+
+To delete a single invite token the invite token needs to be specified (as they are stored hashed). Instead of using `-` and interactively entering the invite code, you could also use `./invitectl --db invites.db delete --token solitech_UjxcL3ROgF/2wBV44jFOuQ==`.
+
+## Delete all invite tokens
+
+```
+pea@peabox: ./invitectl --db invites.db delete-all
+   • Successfully deleted all invite tokens in database
+```
+