Kong: API tokens using JWT

Created on 26 Oct 2016  路  7Comments  路  Source: Kong/kong

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

  • Tokens are stored as free text hence security concerns as expressed in https://github.com/Mashape/kong/issues/1237
  • Tokens are stored in DB which add communication latency during authetication of poxied APIs and DB can become bottleneck under heavy load. Caching helps, but stateless way would be preferred

The JWT spec seems to solve both of these problems (assuming secret used for signing token is safe)

  • JWT tokens don't need to be stored any where. It can be just provided once and forgotten
  • JWT tokens can be verified without need for communicating with any data store. This stateless nature of JWT helps to scale horizontally without bottlenecks

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

  • Authentication of proxied APIs need to talk to DB to get secret and iss
  • The JWT token generation logic has to be implemented outside kong

Question:
What is the recommended way achieve use case like Github api keys with JWT in kong?

pluginjwt

Most helpful comment

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

  • The secret is configured via environment variable. The JWT plugin reads the secret from this variable
$ export JWT_SECRET=e71829c351aa4242c2719cbfbe671c09
$ kong start
  • Request for creating JWT token for a consumer would construct following claim as payload
// 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

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

All 7 comments

+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

  • The secret is configured via environment variable. The JWT plugin reads the secret from this variable
$ export JWT_SECRET=e71829c351aa4242c2719cbfbe671c09
$ kong start
  • Request for creating JWT token for a consumer would construct following claim as payload
// 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

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

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jeremyjpj0916 picture jeremyjpj0916  路  65Comments

SunshineYang picture SunshineYang  路  39Comments

grillorafael picture grillorafael  路  42Comments

ahmadnassri picture ahmadnassri  路  59Comments

timusketeers picture timusketeers  路  36Comments