Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API tokens using JWT #1772

Closed
endeepak opened this issue Oct 26, 2016 · 8 comments
Closed

API tokens using JWT #1772

endeepak opened this issue Oct 26, 2016 · 8 comments

Comments

@endeepak
Copy link

endeepak commented Oct 26, 2016

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 Storing sensitive information in database #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?

@saamalik
Copy link

+1

@thibaultcha
Copy link
Member

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 :)

@thibaultcha
Copy link
Member

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.

@endeepak
Copy link
Author

endeepak commented Nov 21, 2016

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"
}
  • When consumer makes an API request with the above token, verify the token and populate the consumer details from claim data
// 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

@ksachdev1
Copy link

Reading this post, should I assume that there is no blacklisting of JWT supported by Kong?

@gottfrois
Copy link

@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?

@mvanholsteijn
Copy link
Contributor

@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.

@bungle
Copy link
Member

bungle commented Nov 25, 2020

I am closing this as using an asymmetric signature algorithm should be the preferred way to go.

@bungle bungle closed this as completed Nov 25, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants