Context:
We are planning to expose our APIs to our application users similar to Github api keys. We need rate limiting etc which are implemented beautifully in kong. Our use case can be achieved easily with key auth plugin, but couple of concerns there
The JWT spec seems to solve both of these problems (assuming secret used for signing token is safe)
Problem:
The current JWT plugin seems to generate new pair of issuer field (iss / called as key there) and secret per consumer for signing. These values are stored in DB
Question:
What is the recommended way achieve use case like Github api keys with JWT in kong?
+1
Authentication of proxied APIs need to talk to DB to get secret and iss
What other solutions are you envisioning that would allow Kong nodes to be aware of your consumer's credentials (signing the tokens) all the while not storing them in the database at the same time?
Tokens are stored as free text
We would welcome contributions for this, but at the same time, such a contribution would need to find an elegant way of dealing with this issue across the entire code base, providing a proper DB encryption for all secrets stored in both Cassandra and Postgres. This is on our TODO list.
The JWT token generation logic has to be implemented outside kong
That is correct. Contributions welcomed :)
PS: at the same time, you can use RS256 to sign your tokens, for which Kong will only require you to store the public key in the DB.
Authentication of proxied APIs need to talk to DB to get secret and iss
What other solutions are you envisioning that would allow Kong nodes to be aware of your consumer's credentials (signing the tokens) all the while not storing them in the database at the same time?
Avoiding DB access for fetching secret : I was hoping it would be more like nginx plus jwt token support. In this case, a single secret is needed on server side as configuration. The configuration is loaded on server startup and no db access for fetching secret. The jwt plugin for caddy also has similar implementation where secret is configured using a environment variable JWT_SECRET
Avoiding DB access for fetching consumer details : The sub field in jwt claim can have consumer id and other public claim fields can be used for consumer username and customid (explained below). An example for this can be found in auth0 jwt docs
To draw parallels in kong, the flow in kong could be as follows
$ export JWT_SECRET=e71829c351aa4242c2719cbfbe671c09
$ kong start
// Claim payload for creating token
{
"sub": "7bce93e1-0a90-489c-c887-d385545f8f4b", // consumer id
"username": "john_doe",
"customid": "1234"
}
// Request for creating JWT token for consumer
$ curl -X POST http://kong:8001/consumers/{consumer}/jwt
HTTP/1.1 201 Created
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3YmNlOTNlMS0wYTkwLTQ4OWMtYzg4Ny1kMzg1NTQ1ZjhmNGIiLCJ1c2VybmFtZSI6ImpvaG5fZG9lIiwiY3VzdG9taWQiOiIxMjM0In0.V7DGbqOPS_MlZOnL_jyFYIH-mxAe-e1l3uuhYgr0vGM"
}
md5-f25f2cf6b2dc1d2395b959f748038d79
// From above token and secret. The upstream headers are populated as below
X-Consumer-ID: 7bce93e1-0a90-489c-c887-d385545f8f4b
X-Consumer-Custom-ID: 1234
X-Consumer-Username: john_doe
None of the consumer tokens are stored in DB, hence no need for encryption / hashing. This assumes the secret for creating token is safe guarded on server side, which would be a minimum requirement even when encryption / hashing mechanism is used for storing sensitive data in DB.
Yes*, only If blacklisting tokens is not needed.
No*, If blacklisting is needed. You'll have to store the black listed tokens in DB as explained here. Even with this, it would be just one DB call vs 2 DB calls needed now (1 for retrieving secret + 1 for retrieving consumer details)
@thibaultcha Thanks for suggesting RS256
Reading this post, should I assume that there is no blacklisting of JWT supported by Kong?
@endeepak exposing consumer metadata as http headers (one http header for one consumer attribute) might be problematic if you start having a big enough claim payload. Would be nice if kong expose the base64 encoded string that we just need to decode and deal with it.
What do you think?
@endeepak, I would suggest using RS256 encryption, requiring you only to store only the public key of your users for validation. Very safe, as you do not have knowledge of the private key of your caller and you do not have to communicate any secrets to the users.
Most helpful comment
Avoiding DB access for fetching secret : I was hoping it would be more like nginx plus jwt token support. In this case, a single secret is needed on server side as configuration. The configuration is loaded on server startup and no db access for fetching secret. The jwt plugin for caddy also has similar implementation where secret is configured using a environment variable
JWT_SECRETAvoiding DB access for fetching consumer details : The
subfield in jwt claim can have consumer id and other public claim fields can be used for consumer username and customid (explained below). An example for this can be found in auth0 jwt docsTo draw parallels in kong, the flow in kong could be as follows
Security aspect
None of the consumer tokens are stored in DB, hence no need for encryption / hashing. This assumes the secret for creating token is safe guarded on server side, which would be a minimum requirement even when encryption / hashing mechanism is used for storing sensitive data in DB.
So no DB access at all?
Yes*, only If blacklisting tokens is not needed.
No*, If blacklisting is needed. You'll have to store the black listed tokens in DB as explained here. Even with this, it would be just one DB call vs 2 DB calls needed now (1 for retrieving secret + 1 for retrieving consumer details)
@thibaultcha Thanks for suggesting RS256