Package: bootleg-jwt
bootleg-jwtbootleg-jwtaims to mimic JSON Web Tokens in a simple,pydanticway.New for v0.3.0Version 0.3.0 extends v0.2.x with backwards compatible addition of the_saltand_personarguments. When these arguments are passed alongside a token, the token's hash is generated using them. Note: the_saltand_personarguments may not be longer than 16 bytes. This is a limitation of the blake2b hashing algorithm. If a string is supplied, it will be encoded to utf-8 and truncated automatically. Otherwise, any bytestring longer than 16 bytes will fail validation. This is by design._saltand_personallow the token to be namespaced and salted. This provides an extra layer of validation, allowing implementations ofBootlegJWTto perform more checks on tokens, other than what is baked in. This would allow, for example, invalidating all tokens with a particular salt or namespace.Table of ContentsGenerate a tokenValidate a tokenRenew a tokenGenerate a tokenfrombootleg_jwtimportBootlegJWT,Payload,header,bodyfrompydanticimportBaseModelfromosimportenviron# An environment variable is required.SECRET="some-secret-key"DURATION=60*60# Token expires after this many secondsTYPE="Testing Token"# An arbitrary nameenviron['SECRET']=SECRET# This module depends upon an environment# variable `SECRET`. You may also set this# secret in a `.env` file in your project's root,# or by using `export SECRET="secret"`## These two pydantic models are simple examples. They may have arbitrary names and data. They must only map to Token.body.user and Token.body.dataclassUserData(BaseModel):id:intusername:strclassBodyData(BaseModel):info:strvalue:boolpayload_user=UserData(id=69,username="nice")payload_body=BodyData(info="Some Information",value=True)payload=Payload(header=header(duration=DURATION,type=TYPE),body=body(user=payload_user,data=payload_body))generate=BootlegJWT(payload=payload)token=generate.TOKENencoded=generate.ENCODEDjson=generate.JSONvalidate=generate.VALIDdivider="\n------------------------------\n"print(token,divider,encoded,divider,json,divider,validate)Output (click to expand):header=Header(type='TestingToken',duration=Duration(unit=Unit(type='time',name='seconds',shorthand='s'),value=3600),created=Timestamp(unit=Unit(type='time',name='secondssinceepoch',shorthand='s+epoch'),value=1677382369),expires=Timestamp(unit=Unit(type='time',name='secondssinceepoch',shorthand='s+epoch'),value=1677385969))body=Body(user=UserData(id=69,username='nice'),data=BodyData(info='SomeInformation',value=True))signature=Hash(value=b'e0b99c4eca2811bd9d164185219a283a4fddc2129ec0d2b3e5ba7b22596e4c7b8ac6d7b7c81812b50ace0a5b6d0be3ce5f977f753069d951bf15d13f179014df',algorithm='blake2b',keyed=True,salt=b'',person=b'')------------------------------b'eyJoZWFkZXIiOiB7InR5cGUiOiAiVGVzdGluZyBUb2tlbiIsICJkdXJhdGlvbiI6IHsidW5pdCI6IHsidHlwZSI6ICJ0aW1lIiwgIm5hbWUiOiAic2Vjb25kcyIsICJzaG9ydGhhbmQiOiAicyJ9LCAidmFsdWUiOiAzNjAwfSwgImNyZWF0ZWQiOiB7InVuaXQiOiB7InR5cGUiOiAidGltZSIsICJuYW1lIjogInNlY29uZHMgc2luY2UgZXBvY2giLCAic2hvcnRoYW5kIjogInMrZXBvY2gifSwgInZhbHVlIjogMTY3NzM4MjM2OX0sICJleHBpcmVzIjogeyJ1bml0IjogeyJ0eXBlIjogInRpbWUiLCAibmFtZSI6ICJzZWNvbmRzIHNpbmNlIGVwb2NoIiwgInNob3J0aGFuZCI6ICJzK2Vwb2NoIn0sICJ2YWx1ZSI6IDE2NzczODU5Njl9fSwgImJvZHkiOiB7InVzZXIiOiB7ImlkIjogNjksICJ1c2VybmFtZSI6ICJuaWNlIn0sICJkYXRhIjogeyJpbmZvIjogIlNvbWUgSW5mb3JtYXRpb24iLCAidmFsdWUiOiB0cnVlfX0sICJzaWduYXR1cmUiOiB7InZhbHVlIjogImUwYjk5YzRlY2EyODExYmQ5ZDE2NDE4NTIxOWEyODNhNGZkZGMyMTI5ZWMwZDJiM2U1YmE3YjIyNTk2ZTRjN2I4YWM2ZDdiN2M4MTgxMmI1MGFjZTBhNWI2ZDBiZTNjZTVmOTc3Zjc1MzA2OWQ5NTFiZjE1ZDEzZjE3OTAxNGRmIiwgImFsZ29yaXRobSI6ICJibGFrZTJiIiwgImtleWVkIjogdHJ1ZSwgInNhbHQiOiAiIiwgInBlcnNvbiI6ICIifX0='------------------------------{"header":{"type":"Testing Token","duration":{"unit":{"type":"time","name":"seconds","shorthand":"s"},"value":3600},"created":{"unit":{"type":"time","name":"seconds since epoch","shorthand":"s+epoch"},"value":1677382369},"expires":{"unit":{"type":"time","name":"seconds since epoch","shorthand":"s+epoch"},"value":1677385969}},"body":{"user":{"id":69,"username":"nice"},"data":{"info":"Some Information","value":true}},"signature":{"value":"e0b99c4eca2811bd9d164185219a283a4fddc2129ec0d2b3e5ba7b22596e4c7b8ac6d7b7c81812b50ace0a5b6d0be3ce5f977f753069d951bf15d13f179014df","algorithm":"blake2b","keyed":true,"salt":"","person":""}}------------------------------TrueValidate a tokenfrombootleg_jwtimportBootlegJWT,Payload,header,bodyfrompydanticimportBaseModelfromosimportenviron# An environment variable is required.SECRET="some-secret-key"DURATION=60*60# Token expires after this many secondsTYPE="Testing Token"# An arbitrary nameenviron['SECRET']=SECRET# This module depends upon an environment# variable `SECRET`. You may also set this# secret in a `.env` file in your project's root,# or by using `export SECRET="secret"`## These two pydantic models are simple examples. They may have arbitrary names and data. They must only map to Token.body.user and Token.body.dataclassUserData(BaseModel):id:intusername:strclassBodyData(BaseModel):info:strvalue:boolpayload_user=UserData(id=69,username="nice")payload_body=BodyData(info="Some Information",value=True)payload=Payload(header=header(duration=DURATION,type=TYPE),body=body(user=payload_user,data=payload_body))divider="\n------------------------------\n"defgenerate(payload):generate=BootlegJWT(payload=payload)decoded=generate.DECODEDencoded=generate.ENCODEDjson=generate.JSONvalidate=generate.VALIDprint(decoded,divider,encoded,divider,json,divider,validate)returnencodeddefvalidate_token(token):validate_token=BootlegJWT(token=token)v_decoded=validate_token.DECODEDv_json=validate_token.JSONv_valid=validate_token.VALIDprint(v_decoded,divider,v_json,divider,v_valid)validate_token(generate(payload))Output (click to expand):header=Header(type='TestingToken',duration=Duration(unit=Unit(type='time',name='seconds',shorthand='s'),value=3600),created=Timestamp(unit=Unit(type='time',name='secondssinceepoch',shorthand='s+epoch'),value=1677383225),expires=Timestamp(unit=Unit(type='time',name='secondssinceepoch',shorthand='s+epoch'),value=1677386825))body=Body(user=UserData(id=69,username='nice'),data=BodyData(info='SomeInformation',value=True))signature=Hash(value=b'9a6a3fc5c866442ee886c1d20f44fe49da29be4e56fd6f40a1c3e23f672d801c0d787f9f239265477da1339fffc41754f16a0899f5955aa0ed7602693919071d',algorithm='blake2b',keyed=True,salt=b'',person=b'')------------------------------b'eyJoZWFkZXIiOiB7InR5cGUiOiAiVGVzdGluZyBUb2tlbiIsICJkdXJhdGlvbiI6IHsidW5pdCI6IHsidHlwZSI6ICJ0aW1lIiwgIm5hbWUiOiAic2Vjb25kcyIsICJzaG9ydGhhbmQiOiAicyJ9LCAidmFsdWUiOiAzNjAwfSwgImNyZWF0ZWQiOiB7InVuaXQiOiB7InR5cGUiOiAidGltZSIsICJuYW1lIjogInNlY29uZHMgc2luY2UgZXBvY2giLCAic2hvcnRoYW5kIjogInMrZXBvY2gifSwgInZhbHVlIjogMTY3NzM4MzIyNX0sICJleHBpcmVzIjogeyJ1bml0IjogeyJ0eXBlIjogInRpbWUiLCAibmFtZSI6ICJzZWNvbmRzIHNpbmNlIGVwb2NoIiwgInNob3J0aGFuZCI6ICJzK2Vwb2NoIn0sICJ2YWx1ZSI6IDE2NzczODY4MjV9fSwgImJvZHkiOiB7InVzZXIiOiB7ImlkIjogNjksICJ1c2VybmFtZSI6ICJuaWNlIn0sICJkYXRhIjogeyJpbmZvIjogIlNvbWUgSW5mb3JtYXRpb24iLCAidmFsdWUiOiB0cnVlfX0sICJzaWduYXR1cmUiOiB7InZhbHVlIjogIjlhNmEzZmM1Yzg2NjQ0MmVlODg2YzFkMjBmNDRmZTQ5ZGEyOWJlNGU1NmZkNmY0MGExYzNlMjNmNjcyZDgwMWMwZDc4N2Y5ZjIzOTI2NTQ3N2RhMTMzOWZmZmM0MTc1NGYxNmEwODk5ZjU5NTVhYTBlZDc2MDI2OTM5MTkwNzFkIiwgImFsZ29yaXRobSI6ICJibGFrZTJiIiwgImtleWVkIjogdHJ1ZSwgInNhbHQiOiAiIiwgInBlcnNvbiI6ICIifX0='------------------------------{"header":{"type":"Testing Token","duration":{"unit":{"type":"time","name":"seconds","shorthand":"s"},"value":3600},"created":{"unit":{"type":"time","name":"seconds since epoch","shorthand":"s+epoch"},"value":1677383225},"expires":{"unit":{"type":"time","name":"seconds since epoch","shorthand":"s+epoch"},"value":1677386825}},"body":{"user":{"id":69,"username":"nice"},"data":{"info":"Some Information","value":true}},"signature":{"value":"9a6a3fc5c866442ee886c1d20f44fe49da29be4e56fd6f40a1c3e23f672d801c0d787f9f239265477da1339fffc41754f16a0899f5955aa0ed7602693919071d","algorithm":"blake2b","keyed":true,"salt":"","person":""}}------------------------------Trueheader=Header(type='TestingToken',duration=Duration(unit=Unit(type='time',name='seconds',shorthand='s'),value=3600),created=Timestamp(unit=Unit(type='time',name='secondssinceepoch',shorthand='s+epoch'),value=1677383225),expires=Timestamp(unit=Unit(type='time',name='secondssinceepoch',shorthand='s+epoch'),value=1677386825))body=Body(user={'id':69,'username':'nice'},data={'info':'SomeInformation','value':True})signature=Hash(value=b'9a6a3fc5c866442ee886c1d20f44fe49da29be4e56fd6f40a1c3e23f672d801c0d787f9f239265477da1339fffc41754f16a0899f5955aa0ed7602693919071d',algorithm='blake2b',keyed=True,salt=b'',person=b'')------------------------------{"header":{"type":"Testing Token","duration":{"unit":{"type":"time","name":"seconds","shorthand":"s"},"value":3600},"created":{"unit":{"type":"time","name":"seconds since epoch","shorthand":"s+epoch"},"value":1677383225},"expires":{"unit":{"type":"time","name":"seconds since epoch","shorthand":"s+epoch"},"value":1677386825}},"body":{"user":{"id":69,"username":"nice"},"data":{"info":"Some Information","value":true}},"signature":{"value":"9a6a3fc5c866442ee886c1d20f44fe49da29be4e56fd6f40a1c3e23f672d801c0d787f9f239265477da1339fffc41754f16a0899f5955aa0ed7602693919071d","algorithm":"blake2b","keyed":true,"salt":"","person":""}}------------------------------TrueRenew a tokenUsingBootlegJWT.renew(token), you may pass a token to BootlegJWT in bytestring form. This function will return an instance ofBootlegJWTwith a new token and expiration date, retaining all of the input token's properties.