Package: apistar_jwt
apistar-jwtJSON Web Token Component for use withAPI Star >= 0.4.Installation$ pip install apistar-jwtAlternatively, install throughpipenv.$ pipenv install apistar-jwtUsageRegister theJWTComponent with your APIStar app.fromapistarimportAppfromapistar_jwt.tokenimportJWTroutes=[# ...]components=[JWT({'JWT_SECRET':'BZz4bHXYQD?g9YN2UksRn7*r3P(eo]P,Rt8NCWKs6VP34qmTL#8f&ruD^TtG',}),]app=App(routes=routes,components=components)Inject theJWTcomponent in your login function and use it to encode the JWT.fromapistarimportexceptions,types,validatorsfromapistar_jwt.tokenimportJWTclassUserData(types.Type):email=validators.String()password=validators.String()deflogin(data:UserData,jwt:JWT)->dict:# do some check with your database here to see if the user is authenticateduser=db_login(data)ifnotuser:raiseexceptions.Forbidden('Incorrect username or password.')payload={'id':user.id,'username':user.email,'random_data':'102310',}token=jwt.encode(payload)iftokenisNone:# encoding failed, handle errorraiseexceptions.BadRequest()return{'token':token}Inject theJWTUsercomponent in any resource where you want authentication with the provided JWT.fromapistar_jwt.tokenimportJWTUserdefwelcome(user:JWTUser)->dict:message=f'Welcome{user.username}#{user.id}, here is your random data:{user.token["random_data"]}'return{'message':message}NoteRequests made with JWT The token must be passed as anAuthorizationheader using theBearerscheme in requests made to a resource.$curl-i-H"Accept: application/json"-H"Content-Type: application/json"-H"Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoxfQ.fCqeAJGHYwZ9y-hJ3CKUWPiENOM0xtGsMeUWmIq4o8Q"http://localhost:8080/some-resource-requiring-jwt-authDecoratorsWe provide two decorators for convenience to enforce authentication required or allow anonymous users for a route:fromapistar_jwt.tokenimportJWTUserfromapistar_jwt.decoratorsimportanonymous_allowed,authentication_required@authentication_requireddefauth_required(request:http.Request,user:JWTUser):returnuser.__dict__@anonymous_alloweddefanon_allowed(request:http.Request,user:JWTUser):ifuser:returnuser.__dict__returnNoneThe@authentication_requireddecorator will enforce the user to be logged in for that route. Meanwhile the@anonymous_allowedwill setuser: JWTUser=Noneand allow anonymous users to hit the route. The default behavior is@authentication_requiredso you do not need to annotate with this decorator, it is just to help your code be explicit.SettingsThere are two settings this package uses to identify theusernameanduser_idkeys in the JWT payload, they are by default:{'JWT_USER_ID':'id','JWT_USER_NAME':'username',}If your JWT uses some other kind of key, override these keys when you instantiate your component:fromapistar_jwt.tokenimportJWTcomponents=[JWT({'JWT_USER_ID':'pk','JWT_USER_NAME':'email',})]JWT_WHITE_LISTallows you to specify a list of route functions that will not require JWT authentication. This is useful if you have setup a default authentication policy but want to open up certain routes, especially ones that might be in third party packages or in apistar itself like the schema docs.fromapistar_jwt.tokenimportJWTcomponents=[JWT({'JWT_WHITE_LIST':['serve_schema','home'],})]In this instance, theserve_schemaandhomeRoutes will not require JWT authentication.JWT_ALGORITHMSis related to the algorithms used for decoding JWTs. By default we only use 'HS256' but JWT supports passing an array ofsupported algorithmswhich it will sequentially try when attempting to decode.fromapistar_jwt.tokenimportJWTcomponents=[JWT({'JWT_ALGORITHMS':['HS256','RSA512'],})]JWT_SECRETis a long, randomized, secret key that should never be checked into version control.fromapistar_jwt.tokenimportJWTcomponents=[JWT({'JWT_SECRET':'QXp4Z83.%2F@JBiaPZ8T9YDwoasn[dn)cZ=fE}KqHMJPNka3QyPNq^KnMqL$oCsU9BC?.f9,oF2.2t4oN?[g%iq89(+'})]For all other settings, useJWT_OPTIONSkey which will pass them along to the underlyingPyJWTlibrary when decoding.fromapistar_jwt.tokenimportJWTcomponents=[JWT({'JWT_OPTIONS':{'issuer':'urn:foo','audience':'urn:bar','leeway':10,},})]Quick rundown of the options:audienceis the urn for this applications audience, it must match a value in theaudkey of the payload.Read more about audience claim.issueris the urn of the application that issues the token, it must match a value in theisskey of the payload.Read more about the issuer claimleewayis the number of seconds of margin an expiration time claim in the past will still be valid for.A fully customizedJWTcomponent would like like the following:fromapistar_jwt.tokenimportJWTcomponents=[JWT({'JWT_ALGORITHMS':['HS256','RSA512'],'JWT_USER_ID':'pk','JWT_USER_NAME':'email','JWT_SECRET':'QXp4Z83.%2F@JBiaPZ8T9YDwoasn[dn)cZ=fE}KqHMJPNka3QyPNq^KnMqL$oCsU9BC?.f9,oF2.2t4oN?[g%iq89(+','JWT_OPTIONS':{'issuer':'urn:foo','audience':'urn:bar','leeway':10,},'JWT_WHITE_LIST':['serve_schema'],})]DevelopingThis project usespipenvto manage its development environment, andpytestas its tests runner.  To install development dependencies:pipenv install --devTo run tests:pipenv shell
pytestThis project usesCodecovto enforce code coverage on all pull requests.  To run tests locally and output a code coverage report, run:pipenv shell
pytest --cov=apistar_test/HISTORY0.4.2Everything is now a top level export as well, e.g.from apistar_jwt import JWT(thanks @jgiradet)0.4.1Added decorator support,@anonymous_allowedand@authentication_requiredAdded back in test suiteUpdated typings and fixed a bug with instantiatingJWTcomponent0.4.0 ** BREAKING CHANGE **Apistar JWT updated to support Apistar >= 0.4. Pin to 0.3.3 for Apistar 0.3.x support0.3.3Update dev deps so we are using metadata 2.1 spec for pypi.0.3.2Updates to pin dependencies for Apistar 0.3.x and add Markdown rendering to pypi.org0.3.1Release for Apistar 0.3.x