JWT Authenticator (Python + Flask)
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
Alfred b7d265c1ee Add role field to returned data 1年前
controllers Add role field to returned data 1年前
imgs Finish README.md 1年前
models Avoid repeated username in the same app 1年前
requirements Add CORS 1年前
resources Update README and jawth tool 1年前
tests Avoid repeated username in the same app 1年前
views Avoid repeated username in the same app 1年前
.gitattributes Apply a boilerplate for project structure 1年前
.gitignore First tests 1年前
README.md Update README and jawth tool 1年前
app.py Add CORS 1年前
config.py Set port on config 1年前
run.py Set port on config 1年前
wsgi.py Finish README.md 1年前

README.md

JaWTh

JWT Authenticator coded in python 3 using Flask. It publishes several end points to manage users and applications and the corresponding credentials.

How it works?

It stores applications and users. Applications have a name and a secret key for generating JWT. Users have a username, an encrypted password, and a timestamp of the last login between other fields. Each user corresponds to an application.

When a user makes a request of login in that application JaWTh compares the passwords, if the request is valid also signs a JWT with the username, the user uid, and the timestamp. JaWTh returns this info as token to the client. Then the client will send this JWT in each request for making any action into the application.

When the application receives the JWT, decodes the token and will apply the required actions for the user indicated into the token.

Security concerns

  • The timestamp allows to expire tokens at application level.
  • Passwords are stored encrypted (of course!).
  • The secret key for signing tokens should only be known by the encoder and the decoder (JaWth and the application).
  • To make changes into JaWTh you must know a password and its own secret key for JWT.
  • It forces the HS256 algorithm. So clients are not allowed to set the signature algorithm in the HTTP, with it they cannot set the signature to alg=none.

Possible improvements

  • For banning users it could make requests to webhooks implemented into the application target.
  • It could manage mailing for recovering passwords and confirm accounts. Also sign ups.
  • It could be an application key for letting them to add and remove users.
  • Specify CORS by app.
  • Improve error messages.

Using it

Clients comunicate with JaWTh using HTTP requests to the different end points. It is required to provide an auth request header with the value jwt <jwt>. Below you can find examples.

To generate the JWT there are multiple libraries for the most popular programming languages. jwt.io offers a tool to do it directly on their website.

The JSON to be encoded would be one that includes the JAWTH_KEY into the field password. If the request requires to senddata the JSON should also include another field with the field data.

Here is a generated JWT for a request that no requires to send data:

And here one that requires to send data:

Configuring and launching

To configure JaWTht there is a config file into the project root folder. It’s not recommended to change that but to create a new one. To specify the execution of JaWTh to use that one define a JAWTH_CONFIG environment variable with the path of the new config file.

Your config file should define the next variables:

  • DEBUG: Set to False
  • SECRET_KEY: The JaWTh secret key, the one to use to sign and decode those request sent to JaWTh.
  • JAWTH_KEY: The JaWTh password, the one to use on the JWT.
  • SQLALCHEMY_DATABASE_URI: The database uri.

Two examples of database uri are:

  • Sqlite: sqlite:////tmp/database.db
  • PostgreSQL: postgresql://postgres:mysecretpassword@127.0.0.1:5432/jawth

To use PostgreSQL remember to create a database before launching for first time JaWTh. For example: create database jawth;

To execute a JaWTh development version launch the run.py script.

To run it using Gunicorn use the wsgi.py script: gunicorn --bind 0.0.0.0:8000 wsgi:app

Examples

Here is a list of examples of how to use some of the end points.

List applications [Admin]

curl --request GET \
  --url http://127.0.0.1:5000/applications \
  --header 'auth: jwt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXNzd29yZCI6IkpBV1RIUEFTU1dPUkQifQ.w1w-sVSeIs4Z9pHtFuLx1dnnoK1MCg-zKW4JS9SKFYg' \
  --header 'content-type: application/json'

Create application [Admin]

curl --request POST \
  --url http://127.0.0.1:5000/applications \
  --header 'auth: jwt eyJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IkpBV1RIUEFTU1dPUkQiLCJkYXRhIjp7Im5hbWUiOiJ0ZXN0YXBwIiwic2VjcmV0IjoibmFuYW5hbmEifX0.Pb63sGNUFz5ebfzo-7pkic64MOPS-WgkKyaqncX1spQ' \
  --header 'content-type: application/json' \
  --data '{
	"name": "testapp",
	"secret": "nananana"
}'

Create user in application ‘testapp’ [Admin]

curl --request POST \
  --url http://127.0.0.1:5000/testapp/users \
  --header 'auth: jwt eyJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IkpBV1RIUEFTU1dPUkQiLCJkYXRhIjp7InVzZXJuYW1lIjoidXNlcjEiLCJwYXNzd29yZCI6InBhc3MxMjM0In19.y-gw7kpHdvuClAbfnxsAmloG3gOR_06_3x6SrNEjstg' \
  --header 'content-type: application/json' \
  --data '{
	"username": "user1",
	"password": "pass1234"
}'

List users in application ‘testapp’ [Admin]

curl --request GET \
  --url http://127.0.0.1:5000/testapp/users \
  --header 'auth: jwt eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXNzd29yZCI6IkpBV1RIUEFTU1dPUkQifQ.w1w-sVSeIs4Z9pHtFuLx1dnnoK1MCg-zKW4JS9SKFYg' \
  --header 'content-type: application/json'

Change ‘user1’ password in application ‘testapp’ [Admin]

curl --request PATCH \
  --url http://127.0.0.1:5000/testapp/users/user1 \
  --header 'auth: jwt eyJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IkpBV1RIUEFTU1dPUkQiLCJkYXRhIjp7InBhc3N3b3JkIjoicGE1NXcwcmQifX0.p4Kj_isPF1jUszIxCkhS_5soFI7XWgFIW19Bnur8-ss' \
  --header 'content-type: application/json' \
  --data '{
	"password": "pa55w0rd"
}'

Login ‘user1’ with password ‘pa55w0rd’ in application ‘testapp’ [User]

curl --request POST \
  --url http://127.0.0.1:5000/testapp/login \
  --header 'content-type: application/json' \
  --data '{
	"username": "user1",
	"password": "pa55w0rd"
}'

Change ‘user1’ password [User]

Here we need a proper token. This one uses the time of last login: 2018-09-12 12:44:51.715047

curl --request POST \
  --url http://127.0.0.1:5000/testapp/user1/change_password \
  --header 'auth: jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InVzZXIxIiwiaWQiOjEsInRpbWVzdGFtcCI6IjIwMTgtMDktMTIgMTI6NDQ6NTEuNzE1MDQ3In0.vjAWSCFUbGsvLBJa3-uCqEtDQ20KS5pc_bucXFOmw2A' \
  --header 'content-type: application/json' \
  --data '{
	"password": "pass1234again",
	"repeated_password": "pass1234again"
}'

Other end points

  • CRUD on all users: POST, GET, PATCH, DELETE ─ /users[/useruid]
  • CRUD on all applications: POST, GET, PATCH, DELETE ─ /application[/appname]