Tyk.io + Auth0

Imported Google Group message. Original thread at: Redirecting to Google Groups Import Date: 2016-01-19 21:43:28 +0000.
Sender:Carl Krauss.
Date:Friday, 15 January 2016 00:58:56 UTC.

Hey All,

We’re in the middle of doing some testing with a 3rd party auth service. (https://auth0.com) We wanted to possibly use tyk.io but are having some trouble getting things working with the JWT, and I was wondering if any of you might be able to point us in the right direction.

So the basics…

Setup an API route that routes to one of our backend apis, pretty strait forward. We turned off auth to make sure everything worked. +1

Now we enabled JWT w/ hmac on that endpoint. We proceeded to add a new key and for simplicity sake we’ll just use the work “secret”. Cool, so now we have this random key id thats generated storing our shared secret. Whipped up a test token and put the key in the “kid” section of the header. Sent it through and it worked. +1

Next we wanted to use a token generated from auth0. Now we’ve run into some problems…
1 - The tokens generated by auth0 don’t have a “kid” section in the header. womp womp. While reading through some docs it looks like it falls back to “sub” in the claims section. Ok, that might work.
(tyk/middleware_jwt.go at dd8e29f1ddd44646f54b9013e5c3f845687ce8ed · TykTechnologies/tyk · GitHub)
However, When actually sending these requests through the logs show that tyk didn’t find a suitable key, which is a bit confusing.
INFO[10844] Attempted JWT access with non-existent key. key= key_present=false origin=10.40.8.28:55703 path=/some/test/
So that’s problem 1.

2 - Auth0 populates the “sub” claims section with (what looks like) the user id. “sub”: “auth0|1234567896433” This is obviously going to look different for every user, so we’d have to create new “keys” everytime a user is created with the same shared secret? That doesn’t seem right.

3 - Let’s say we hack all of that together, the last problem is that auth0 base64 encodes the it’s secret and I don’t see a good way to enable that in the tyk interface.

Any help would be appreciated, it looks like a pretty nice product from what we’ve been able to test so far.

Imported Google Group message.
Sender:Martin Buhr.
Date:Friday, 15 January 2016 13:08:32 UTC.

Hi Carl,

There’s a problem here, because each user will need it’s own ID (key) in Tyk, and since you can’t influence the identifier (sub OR kid) in the JWT that is provided using Auth0 you’re stuck since the Tyk ID (key) will never be the same as the Auth0 ID, although I guess you could use custom tokens to make them match, but that’s not great.

The way Tyk validates JWT’s is that one key has one secret (or public key), so that we can validate that the token does indeed belong to the identity provided, so yes, you would need to share out the secret across tokens if you are validating against a group provider instead of an individual. Our JWT support is very new, so we’ll be improving it as we go. To be honest, adding a single shared secret and having an option to validate against an API-level defined secret would be a great extension :slight_smile:

But there is a way :slight_smile: deep breath

For this (and I’m not sure about your flow), you could use our new Tyk Identity Broker, you send your Auth0 authentication request in one end, and get a short term Tyk (OAuth or regular) token out the other end. I tried it out with Auth0’s password grant flow, and created a standard token with Tyk quite easily:

Tyk Identity Broker profile configuration:

[{
 "ActionType": "GenerateTemporaryAuthToken",
 "ID": "1",
 "IdentityHandlerConfig": {
  "DashboardCredential": "YOUR-DASHBOARD-API-KEY",
  "DisableOneTokenPerAPI": false,
  "TokenAuth": {
   "BaseAPIID": "BASE-API-ID-FOR-ACCESS"
  }
 },
 "MatchedPolicyID": "POLICY-TO-APPLY",
 "OrgID": "YOUR-ORG-ID",
 "ProviderConfig": {
  "OKCode": 200,
  "ResponseIsJson": true,
  "AccessTokenField": "id_token",
  "TargetHost": "https://yourdomain.iso.auth0.com/oauth/ro"
 },
 "ProviderName": "ProxyProvider",
 "Type": "redirect"
}]

You’ll need to set up TIB’s configuration obviously with all your API creds for tyk, then with the above policy loaded, you can make a request via TIB to Auth0:

matyin@local ~>
curl -vX POST http://tib.hostname.com:3010/auth/1/auth0 -d @auth0.json --header "Content-Type: application/json" --header "Host: yourhost.iso.auth0.com"
* Hostname was NOT found in DNS cache
*   Trying 178.62.11.62...
* Connected to xxxxxxxxx (xxx.xxx.xxx.xxx) port 3010 (#0)
> POST /auth/1/auth0 HTTP/1.1
> User-Agent: curl/7.37.1
> Accept: */*
> Content-Type: application/json
> Host: xxx.xxx.auth0.com
> Content-Length: 230
>
* upload completely sent off: 230 out of 230 bytes
< HTTP/1.1 200 OK
< Content-Type: application/json
< Date: Fri, 15 Jan 2016 12:51:23 GMT
< Content-Length: 69
<
* Connection #0 to host xxx.xxx.xxx left intact
{"key_id":"53ac07777cbb8c2d5300000265eacbb3c98445975854d553ce9a7e3e"}

The payload is:

{
 "client_id": "xxxxx",
 "username": "username",
 "password": "password",
 "id_token": "",
 "connection": "Username-Password-Authentication",
 "grant_type": "password",
 "scope": "openid",
 "device": ""
}

Notice that I needed to override the host header in the request, otherwise you get a 403 Forbidden error.

When you examine that key in your dashboard, you’ll see that the JWT is automagically added to the metadata of the session data:

{
 "api_model": {},
 "key_id": "53ac07777cbb8c2d5300000265eacbb3c98445975854d553ce9a7e3e",
 "data": {
  ...
  "meta_data": {
   "AccessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL3R5ay5ldS5hdYRoMC5jb20vIiwic3ViIjoiYXV0aDB8NTY5OGM2NzU5NmEwZTNmNzU0Y2FmMmRkIiwiYXVkIjoidFpBdVJKT0xIasdnU3Z3hGOTRubnZGYkRKTEowbEo0NmkiLDJleHAiOjE0NTI4OTgyODMsImlhdCI6MTQ1Mjg2MjI4M30.PN2HJnPlU032Bh8oMH0fgCH1nF7IHay-7l9YzXTvFFw",
   "AccessTokenSecret": "",
   "AuthProviderSource": "ProxyProvider",
   "AuthProviderUserID": "xKOQOCgTDwk",
   "Origin": "TAP"
  },
  "tags": ["TykOrigin-TAP"]
 }
}

You can then use the header injection module to inject any of those keys into your outbound requests headers so your app can decode and use them. Within TIB, you can set the expiry of a key quite easily by adding Expires: seconds to the IdentityHandlerConfig.TokenAuth section.

Also, if you wanted to use OAuth, you can also use a corresponding client in your gateway to generate an auth token / refresh combo (or just access token if you are doing implicit grant), lots of options :slight_smile: This will keep your Auth0 tokens / JWTs separate from gateway access, prevent you from having to hack anything together and have one provides a validation of identity and the other a temporary way into your API based on that validation.

Hope that helps - I’m afraid anything else will require manipulation of the Tyk code base.

Cheers,
Martin

Imported Google Group message.
Sender:Carl Krauss.
Date:Friday, 15 January 2016 22:26:33 UTC.

Martin – Thanks for the very verbose response. Took a bit to digest it all.

That TIB flow seems a bit more complex than I was hoping for. Wrt the flow, it’s something like this:

  1. User logs in via auth0
  2. Auth0 calls one of our backend services to get the permissions and scopes for services on our backend. This is then added to the jwt.
  3. The user then has the jwt that is used in every subsequent request through the app
  4. Those requests are really just API requests (hopefully) through tyk which are validated with a shared secret (or pub key)
  5. They are then then proxied to their corresponding backend service.

I was thinking that the changes that would have to be made are:

Auth0 - Provide a way to add a “kid” to the header of the jwt’s for a given app or user group? Basically a way to set the key id.
Tyk - Possibly provide a way to not require the key and just use a shared secret given an API endpoint. Also, provide base64 decoding support on the shared secret.

Assuming those changes, I think it would work at that point. Or do I still have something wrong here?

  • show quoted text -

Imported Google Group message.
Sender:Martin Buhr.
Date:Friday, 15 January 2016 22:57:25 UTC.

Hi Carl,

Yeah, sorry about that, but I couldn’t resist tackling a 3rd party integration with our newest service.

Actually for the flow you describe all you need is Tyk to validate the token against a centralised JWT secret (stored in the API Definition) instead of one in the key ID.)

That can be done (mostly) in the middleware directly I should think (you’d need to extend the shared data struct lib tykcommon)

The problem is attribution, you get the request past the first hurdle (auth) but after that, you need to set rate limits and policies on the user across nodes.

Here’s how I’d extend it (this is generalised so it could work for any JWT provider), and can all be done in the middleware:

  • when a token is validated, extract a configurable field from the JWT body, and b64 it (so it’s a clean key and we don’t need to care about any added pipes or sources), then prepend the org id of the API owner (this is how Tyk tokens are structured)
  • one field of the body contains a policy ID, extract this (must be configurable)
  • the middleware GETs this key from the session store (like any other key)
  • if not found, it ADDs the b64 encoded ID we generated from Auth0 to Tyk as-is, based on the policy from the body
  • make sure this key and metadata are stored in the session context as Tyk’s Auth key (so it can be pulled by later middleware) - this might be the trickiest bit as it needs testing, the auth key is requested a lot.

This way, the request remains the same (the JWT is in the same header where your app will expect it), and Tyk can use a generated virtual key based on the metadata of the token to apply rate limits and policy rules etc.

Most importantly, you would get analytics that relate to your actual user that would remain up to date throughout.

Another verbose answer, sorry :slight_smile:

I will put this on the roadmap for 1.10 (which is a ways off), if you or your team fancy tackling it, open a ticket on GH and we’ll be more than happy to collaborate (develop branch).

Cheers,
Martin


From: Carl Krauss [email protected]
Sent: Friday, January 15, 2016 22:26
Subject: Re: Tyk.io + Auth0
To: Tyk Community Support [email protected]

Martin – Thanks for the very verbose response. Took a bit to digest it all.

That TIB flow seems a bit more complex than I was hoping for. Wrt the flow, it’s something like this:

  1. User logs in via auth0
  2. Auth0 calls one of our backend services to get the permissions and scopes for services on our backend. This is then added to the jwt.
  3. The user then has the jwt that is used in every subsequent request through the app
  4. Those requests are really just API requests (hopefully) through tyk which are validated with a shared secret (or pub key)
  5. They are then then proxied to their corresponding backend service.

I was thinking that the changes that would have to be made are:

Auth0 - Provide a way to add a “kid” to the header of the jwt’s for a given app or user group? Basically a way to set the key id.
Tyk - Possibly provide a way to not require the key and just use a shared secret given an API endpoint. Also, provide base64 decoding support on the shared secret.

Assuming those changes, I think it would work at that point. Or do I still have something wrong here?

On Thursday, January 14, 2016 at 4:58:56 PM UTC-8, Carl Krauss wrote:
Hey All,

We’re in the middle of doing some testing with a 3rd party auth service. ( https://auth0.com) We wanted to possibly use tyk.io but are having some trouble getting things working with the JWT, and I was wondering if any of you might be able to point us in the right direction.

So the basics…

Setup an API route that routes to one of our backend apis, pretty strait forward. We turned off auth to make sure everything worked. +1

Now we enabled JWT w/ hmac on that endpoint. We proceeded to add a new key and for simplicity sake we’ll just use the work “secret”. Cool, so now we have this random key id thats generated storing our shared secret. Whipped up a test token and put the key in the “kid” section of the header. Sent it through and it worked. +1

Next we wanted to use a token generated from auth0. Now we’ve run into some problems…
1 - The tokens generated by auth0 don’t have a “kid” section in the header. womp womp. While reading through some docs it looks like it falls back to “sub” in the claims section. Ok, that might work.
( tyk/middleware_jwt.go at dd8e29f1ddd44646f54b9013e5c3f845687ce8ed · TykTechnologies/tyk · GitHub)
However, When actually sending these requests through the logs show that tyk didn’t find a suitable key, which is a bit confusing.
INFO[10844] Attempted JWT access with non-existent key. key= key_present=false origin= 10.40.8.28:55703 path=/some/test/
So that’s problem 1.

2 - Auth0 populates the “sub” claims section with (what looks like) the user id. “sub”: “auth0|1234567896433” This is obviously going to look different for every user, so we’d have to create new “keys” everytime a user is created with the same shared secret? That doesn’t seem right.

3 - Let’s say we hack all of that together, the last problem is that auth0 base64 encodes the it’s secret and I don’t see a good way to enable that in the tyk interface.

Any help would be appreciated, it looks like a pretty nice product from what we’ve been able to test so far.


You received this message because you are subscribed to the Google Groups “Tyk Community Support” group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To view this discussion on the web, visit https://groups.google.com/d/msgid/tyk-community-support/198ba5fc-559f-4b7e-9b00-9aca4c72ea0c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Imported Google Group message.
Sender:Carl Krauss.
Date:Friday, 15 January 2016 23:42:47 UTC.

Martin,

I did see that in the docs somewhere but when I tried it, it didn’t seem to work.

“jwt_data”: {
“secret”: “Secret”
}
And maybe this is just my lack of familiarity with tyk, but when I exported the config of one of the API endpoints it wasn’t in the json config file. What’s the proper way to set this if I’m using mongodb and redis?

Attribution is definitely still an issue though. But, what if we just used what’s coming back in the “sub” claims as the “user” or “key” that recorded in order to attribute those requests. But, ahh that wouldn’t allow you to apply the policy related things (like rate limiting) to those users. Bummer. Ok, I see where you’re going with this generalized abstraction section and dynamically creating the keys. I’m going to stew on this for a bit.

If this is we could get figured out, it might be worth our time to put some cycles into contributing to this feature.

-Carl

  • show quoted text -

Imported Google Group message.
Sender:Martin Buhr.
Date:Saturday, 16 January 2016 09:37:52 UTC.

Hi Carl,

What I was saying in my last post is that these features don’t exist, they need adding, including centralised JWT. That’s why I wrote a little suggested solution.

As I said, there’s a roadmap and this is on it for 1.10, but it’s a ways off.

So if you want it sooner - you’ll need to make those changes to the middleware and tykcommon yourself.

We’re always happy to help out contributors though, so you wouldn’t be alone :slight_smile:

cheers,
Martin

  • show quoted text -

Hey Martin,

We had a chat with some of the guys from Auth0 today to get their take on using these two technologies together.

A few things that we found out…
1 - They do send the “kid” in the header but only if you’re using the pub/priv key to sign requests. (not shared secret)
2 - They had a potential suggestion that seemed reasonable to take a look at for getting the “kid” for a request.
When creating a new “key” of type jwt in tyk, would it be possible to just add a link to the identity provider’s jwk? usually found at identity.yourdomain.com/.well-known/jwks.json (or like auth0 provides – https://test.auth0.com/.well-known/jwks.json) This would allow you to store the kid that’s passed in the header and not need it to be generated on the validation side. What are your thoughts here?

Totally a side note, but would it be possible to add the word “Bearer” before the token? It seems like that’s the standard way to pass jwt token in the header but tyk seems to omit that.

Hi Carl,

I think for Tyk, there’s some serious changes to the JWT middleware that need to be done to get third parties to play nice as validating providers.

So first off, we’ve got centralised JWT validation in our roadmap:

This will remove the requirement for kid or sub headers altogether since the secret or key will be held within the API definition in Tyk itself (or linked, see below).

Since we want to retain attribution, what will happen is the middleware will generate a short-lived token based on a pre-specified scope field using a one-way hash so that it retains the identity of the user. This key will then be used to pass the request through Tyk, attribute rate limits on a policy basis and in general get the middleware to play nice with all the rest of Tyk’s features without massive changes.

As for linking to a well known JWK, we could extend the feature to allow a JWK cache so that it is fetched every so often (I’ve updated the requirement with this in mind), this is pretty simple.

But this is a long way off implementation. So if you want to do this short term you’ll need to hack it together yourselves to do it within Tyk.

Alternatively, extend TIB to validate the JWT for you in exchange for a token, one of the things we really wanted for TIB was a generic JWT validator so you could trade a JWT for a Tyk token - this would be doing externally what our roadmap suggestion is doing internally).

The second approach would be much faster if you want to take the challenge on yourselves.

Cheers,
Martin

So some work has been done in this, with a test suite:

  • Bearer format supported (transparently)
  • Centralised secrets in the API definition dor third party validation of tokens
  • Virtual session IDs for valid tokens to ensure attribution throughout lifetime of user (even across tokens)
  • JWKs supported (though I couldn’t decide Auth0s certificate, this may still need work)

It’s the develop branch, so will be rolled into master on next cut.

https://github.com/TykTechnologies/tyk/blob/develop/CHANGELOG.md

:smiley:

(The build is failing btw - it’s really unstable ATM!) watch this space.

Edit - All JWT tests pass now.

@Martin Love it!

We’ll pull down develop and test this out. Thanks a bunch.

-Carl

We had a chance to pull down develop. We saw that you guys were working on a different logging mechanism that isn’t public :slightly_smiling:

We’re running at commit 8994e8578c20672d75fa785beadae3f9842acc6d
The handling of auth headers with Bearer works just fine. We did have a question around building the dashboard. Is this included in the tyk repo? If it is, I may have just glossed over it. Did you add these features just to the middleware layer or in the dashboard as well? Specifically adding in the jwk url.

I think we’re going to start modifying some of this to work with our implementation of auth0. What’s your normal flow for contributions? PRs against Master?

So we fixed the logging dependency with an external one (tests passing). So you should be able to build from develop again.

The dashboard is proprietary I’m afraid, and this feature hasn’t been added to it yet. We’re working on the next dashboard release now, but there’s quite a lot of new things, so you’ll need to manage this with the gateway API / file-based only until the new dash is ready.

Contributions go against develop since master is stable, appreciate all the help we can get :slightly_smiling:

Cheers,
Martin

Successful Auth0 and Tyk integration example here.

1 Like

Follow up: Auth0 integration is very very easy with tyk 2.1:

https://tyk.io/2016/05/17/integrate-tyk-auth0/

Hi Martin,

I am able to integrate Auth0 and Tyk based upon your article - many thanks.

Just one question considering validation of the JWT signature – how does Tyk validate this signature since it is not aware of the certificate?

All the best,
Robin

Hi Robin,

Good to hear :slight_smile:

The reason Tyk doesn’t need to know the feet is because it will fetch the keys from Auth0 from their discovery endpoint, this is part of the beauty of the OpenID Connect protocol, it allows an issuer to rotate keys and publish them centrally.

Cheers,
Martin

Nice - I was not aware of this! Thanks!!!