Extending Tyk with gRPC Authentication Plugins

Tyk Gateway provides multiple authentication mechanism (OAuth2, Auth Token, Basic Auth, OpenId Connect, JWT, etc) out of the box. However, you may have additional business logic that needs to be considered. You don’t have to rewrite your security infrastructure because you need to introduce an API gateway into your stack.  Tyk allows you to extend the capabilities of its gateway with gRPC plugins.

The chain goes like this:

Tyk: Custom Authentication Diagram

  1. Tyk receives a request
  2. Tyk asks the custom middleware server to authenticate it. 
  3. The server returns the auth results back to the gateway. 
  4. If the auth fails, the gateway will return an error response to the requestor. Otherwise, it will continue the request to the downstream

Optionally, you can choose to cache successful authentication responses in memory to improve performance, which will be covered in detail at the end.

The sample authentication server in this example is written in Java.  However, you can use whatever gRPC supported language  you wish.

Not a coder? No worries: you don’t need to write a single line of code today. Everything included in this guide has links to the code and content, hosted on our Tyk GitHub where you can easily fork, clone, (and star) it.

Prerequisites

Let’s get Kraken

First we’re going to set up our Java server with our business logic and run it so it is ready to accept connections.  Next, we’ll set up Tyk to use our Java server for custom authentication. Then we’ll see it all work!

1. Setup the gRPC server

Clone this repo.  This code is ready to go, we don’t need to make any modifications.
https://github.com/TykTechnologies/tyk-plugin-coprocess-grpc-java-custom-auth/tree/master

Now, we can run the server by running gradle run from command line.  Give this a minute to come up:

$ gradle run
> Task :run
Initializing gRPC server.
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

2. Setup TYK to use the custom authentication plugin

First, we must enable coprocess middlewares at the gateway level.   Edit the Tyk.conf to include these settings:

"coprocess_options" : {
  "enable_coprocess": true,
  "coprocess_grpc_server": "tcp://localhost:5555"
},

Notice the server port matches what we have in the gRPC server’s TykMiddleware.java port

public class TykMiddleware {
  private static final Logger logger = Logger.getLogger(TykMiddleware.class.getName());
  static Server server;
  static int port = 5555;
  …
}

Next, let’s set up our API to do custom authentication.   Switch the API’s Authentication mode to Custom Authentication (Plugin):

Finally, at the top of the API designer page, select RAW API DEFINITION and set driver to grpc under custom_middleware:

 "custom_middleware": {
    "driver": "grpc"
 ...
 },

Done!  Now if we query our Tyk endpoint, Tyk will offload the authentication duties to our custom plugin! 
So let’s see it all working.  If we curl our upstream directly:

$ curl -X get httpbin.org/headers
{
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.54.0"
  }
}

And if we curl through the gateway, which is reverse proxying to the same URL as above: 

$ curl https://www.tyk-test.com:8080/custom-java-auth/headers -H "Authorization:notfoobar"
{
  "error": "Not authorized"
}
$ curl https://www.tyk-test.com:8080/custom-java-auth/headers -H "Authorization:foobar"
{
  "headers": {
    "Accept": "*/*",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.54.0"
  }
}

Note: “foobar” is hard-coded in the Java Auth server. That is the place where you’d place your business logic.

3. (Optional): Caching Authorisation using ID Extractor

Further reading: https://tyk.io/docs/customise-tyk/plugins/rich-plugins/id-extractor/

We can take advantage of Tyk’s built in ID extraction to cache the Authentication results of the gRPC plugin and avoid needing the (respectively slow) plugin to authenticate every API call. If you’ve followed along, it should already be working. Skip the setup instructions to see it in action.

How to set it up:

1) Set “id_extractor” in your API definition:

"custom_middleware": {
  "id_extractor": {
    "extract_from": "header",
    "extract_with": "value",
    "extractor_config": {
      "header_name": "Authorization"
    }
  },
  "driver": "grpc"
},

https://tyk.io/docs/customise-tyk/plugins/rich-plugins/id-extractor/#a-name-when-a-how-to-enable-the-id-extractor

2) Set the id_extractor_deadline field in the session object
TykDispatcher.java

CoprocessSessionState.SessionState session = CoprocessSessionState.SessionState.newBuilder()
    .setRate(1000.0)
    .setPer(1.0)
    .setIdExtractorDeadline(expiryTime)
    .build();

https://tyk.io/docs/customise-tyk/plugins/rich-plugins/id-extractor/#a-name-which-a-when-does-the-id-extractor-run

Now watch the logs of the plugin server as you make requests to the Tyk gateway. It should only be printing request details every 5 seconds, which is the expiry time in the cache. This tells us that the gateway is only needing to authenticate through the plugin every 5 seconds because it has authentication details sitting in the cache as a result of the authentication server’s response.

Summary

And that’s it. In just a few steps we’ve enabled custom authentication middleware using gRPC and Java for the Tyk Gateway.  Did you know that we can also use middleware in other phases of the request and response life cycle?
In addition to gRPC, Tyk can also run Javascript, Lua, Python, and coming soon, native Go plugins.
If you have questions, head to the Tyk Community or tweet us at @tyk_io

Want to learn more about Authentication and Tyk? Check out these resources:

https://tyk.io/blog/how-to-implement-single-sign-on-with-tyk-and-okta/

and