authbot
A Telegram bot for auth and login to a web domain.
This provides a relatively easy way to provide authentication and authorisation for any domain:
- no signup required, just use Telegram
- no email verification required, as you have the authentic Telegram username
- works great on mobile, use the Telegram app
- works great on desktop, use https://web.telegram.org
- minimal code required, just verify the session cookie via Redis
Deploy a bot to authenticate and authorise users for your own domains:
- create an auth bot for your domain e.g.
@adhocDomainAuthBot
via command/newbot
to the Telegram@BotFather
- configure and deploy this auth bot service on your domain for location
/authbot/
e.g. using a Docker image - set the bot webhook via
api.telegram.org
to/authbot/webhook/
- as a user, send the command
/login
- voila!
How it works:
- your authbot will reply to the user with a magic pending login link to itself e.g.
/authbot/login/${user}/${token}
- the user clicks on that
/authbot/login/
link in the chat with the authbot - the authbot HTTP handler for
/authbot/login/
will create the session in Redis, set the session cookie on the HTTP response, and redirect to your landing page for auth'ed visitors e.g./auth
- your site can verify the session cookie via Redis or HTTPS
- the original authoritative (admin) Telegram username can authorise other users
Implementation
We use Koa:
{ api; api; api;
Additionally the following endpoint can allow session validation via HTTP:
if configsessionRoute api;
where this location is deliberately different from /authbot/
so that it must be specifically allowed e.g. by your Nginx API gateway.
The /authbot/login/
HTTP handler will set the session cookie:
assert;assert;const sessionId = token ;const sessionKey = confignamespace 'session' sessionId 'h';const sessionListKey = confignamespace 'session' username 'l';const session = Object;const hmset = await ;ctxcookies;ctx;
For demo purposes we also serve the following landing pages, which would ordinarily be served by the app:
if configdemo api; api; api;
where /auth
and /noauth
are redirects from /authbot/login
The login is created in Redis by the Telegram bot, which provides the /authbot/login/
"magic link."
{ const username name chatId = request; const token = ; const loginKey = confignamespace 'login' username 'h'; let hmset = await ; if hmset await
where a secret token is randomly generated for the "magic link."
{ const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; const charset = '0123456789' + letters + letters; return crypto;}
Config
The default configuration properties are hard-coded as follows:
const configDefault = port: 8080 namespace: 'authbot' redisHost: '127.0.0.1' loginExpire: 30 sessionExpire: 300 cookieExpire: 60000 sendTimeout: 8000 redirectAuth: '/auth' redirectNoAuth: '/noauth' sessionRoute: true loggerLevel: 'debug';
where namespace
is used to prefix auth bot keys in Redis, for pending logins and active sessions.
The following declares meta information about further required configuration:
const configMeta = domain: description: 'HTTPS web domain to auth access' example: 'authdemo.webserva.com' bot: description: 'Telegram Bot name i.e. this authbot' example: 'ExAuthDemoBot' info: 'https://core.telegram.org/bots/api' hint: 'https://telegram.me/BotFather' secret: description: 'Telegram Bot secret' example: 'z7WnDUfuhtDCBjX54Ks5vB4SAdGmdzwRVlGQjWBt' info: 'https://core.telegram.org/bots/api#setwebhook' hint: 'https://github.com/evanx/random-base56' token: description: 'Telegram Bot token' example: '243751977:AAH-WYXgsiZ8XqbzcqME7v6mUALxjktvrQc' info: 'https://core.telegram.org/bots/api#authorizing-your-bot' hint: 'https://telegram.me/BotFather' admin: description: 'Authoritative Telegram username i.e. bootstrap admin user' example: 'evanxsummers' info: 'https://telegram.org' hubRedis: required: false description: 'Remote redis for bot messages, especially for development' example: 'redis://localhost:6333' info: 'https://github.com/evanx/webhook-push' ;
The config
is populated from environment variables as follows:
const configKeys = ;const missingConfigKeys = ;const config = Object;
where we check that an environment variable is not empty, for safety sake.
npm start
If we start the service with missing config via environment variables, the following help is printed:
domain e.g. 'authdemo.webserva.com' "HTTPS web domain to auth access"bot e.g. 'ExAuthDemoBot' "Telegram Bot name i.e. this authbot" see https://core.telegram.org/bots/api see https://telegram.me/BotFather secret e.g. 'z7WnDUfuhtDCBjX54Ks5vB4SAdGmdzwRVlGQjWBt' "Telegram Bot secret" see https://core.telegram.org/bots/api#setwebhook see https://github.com/evanx/random-base56token e.g. '243751977:AAH-WYXgsiZ8XqbzcqME7v6mUALxjktvrQc' "Telegram Bot token" see https://core.telegram.org/bots/api#authorizing-your-bot see https://telegram.me/BotFatheradmin e.g. 'evanxsummers' "Authoritative Telegram username i.e. bootstrap admin user" see https://telegram.orghubRedis e.g. 'redis://localhost:6333' "Remote hub for bot messages via Redis, especially for development" see https://github.com/evanx/webhook-push
Also it prints a npm start
CLI using the example
config properties:
domain='authdemo.webserva.com' \
bot='ExAuthDemoBot' \
secret='z7WnDUfuhtDCBjX54Ks5vB4SAdGmdzwRVlGQjWBt' \
token='243751977:AAH-WYXgsiZ8XqbzcqME7v6mUALxjktvrQc' \
admin='evanxsummers' \
hubRedis='redis://localhost:6333' \
npm start
where this help is generated from configMeta
Build application container
Let's build our application container:
docker build -t authbot https://github.com/evanx/authbot.git
where the image is named and tagged as authbot
Notice that the default Dockerfile
is as follows:
FROM mhart/alpine-node
ADD package.json .
RUN npm install
ADD index.js .
ENV port 8080
EXPOSE 8080
CMD ["node", "--harmony", "index.js"]
Docker run
npm start
with missing configs will print help including for Docker run, which you must edit for your environment
i.e. with your own domain, username, bot name, token, secret etc:
docker run \ --name authbot_test -d \ --network host \ -e NODE_ENV=test \ -e domain='' \ -e bot='' \ -e secret='' \ -e token='' \ -e admin='evanxsummers' \ authbot
Docker notes
This tested on Docker 1.12 (Ubuntu 16.04) and 1.11 (Amazon Linux 2016.09)
docker -v
Docker version 1.12.1, build 23cf638
Docker version 1.11.2, build b9f10c9/1.11.2
cat /etc/issue
Ubuntu 16.04.1 LTS
Amazon Linux AMI release 2016.09
Isolated Redis container and network
In this example we create an isolated network:
docker network create --driver bridge authbot_network
We can create a Redis container named redis_authbot
as follows
docker run --network=authbot_network --name redis_authbot -d redis
We query its IP number and store in shell environment variable redisHost
redisHost=`docker inspect \
--format '{{ .NetworkSettings.Networks.authbot_network.IPAddress }}' redis_authbot`
echo $redisHost
which we check that set e.g. to 172.18.0.2
Finally we run our service container:
docker run --network=authbot_network --name authbot_test -d -p 8080 \ -e NODE_ENV=test \ -e redisHost=$redisHost \ -e domain='' \ -e bot='' \ -e secret='' \ -e token='' \ -e admin='' \ authbot
where we configure redisHost
as the redis_authbot
container.
Note that we:
- use the
redis
isolated network bridge for theredis_authbot
container - name this container
authbot_test
- use the previously built image
authbot:test
Get its IP address:
address=`
docker inspect --format '{{ .NetworkSettings.Networks.authbot_network.IPAddress }}' authbot_test
`
echo $address
That address is set on the API gateway e.g. Nginx, to route HTTP requests for the domain and /authbot
location to the bot.
Auto restart
In a development environment on the cloud interacting with a test bot, it is useful to watch index.js
for changes and restart.
See https://github.com/evanx/authbot/blob/master/docs/auto-restart.md