How to Authenticate APIs Using Kong's OAuth 2.0

Posted by Fugui on July 6, 2023

Authenticate APIs

In this article, we will explore how to use Kong’s OAuth 2.0 plugin to authenticate APIs. Kong is an open-source API gateway that provides powerful capabilities for managing, securing, and scaling APIs. By leveraging Kong’s OAuth 2.0 plugin, you can easily add authentication and authorization mechanisms to your APIs. We will walk through the process of setting up Kong, creating services and routes, enabling the OAuth 2.0 plugin, and securing your APIs with OAuth 2.0 authentication.

Setting up Kong

Before we dive into the authentication process, let’s briefly cover the steps to set up Kong:

To learn how to set up Kong using Docker Compose, please refer to the following guide: Deploying Kong with Docker Compose. The guide provides detailed instructions on how to orchestrate and deploy Kong using Docker Compose.

Authenticate APIs using OAuth 2.0

  1. Create a Service: Use cURL or the Kong Admin API to create a service that represents your API. Specify the service name and the target URL where your API is hosted.
    1
    2
    3
    4
    
    # Create a service
    curl -X POST http://localhost:8001/services \
      --data "name=example-service" \
      --data "url=http://backend-service:5000"
    

    The returned data is as follows:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    {
      "name": "example-service",
      "write_timeout": 60000,
      "retries": 5,
      "tags": null,
      "ca_certificates": null,
      "tls_verify": null,
      "port": 8100,
      "client_certificate": null,
      "connect_timeout": 60000,
      "created_at": 1689911694,
      "updated_at": 1689911694,
      "path": null,
      "protocol": "http",
      "host": "backend-service",
      "read_timeout": 60000,
      "id": "977ab5e5-81b6-465f-ae53-68a61413b6ad",
      "tls_verify_depth": null
    }
    
  2. Create a Route: Define a route for your service to specify how incoming requests should be routed. You can define routing rules based on hostnames, paths, or other criteria.
    1
    2
    3
    4
    5
    
    # Create a route
    curl -X POST http://localhost:8001/services/example-service/routes \
      --data "name=example-endpoint" \
      --data "paths[]=/api/your-endpoint" \
      --data "service.id=977ab5e5-81b6-465f-ae53-68a61413b6ad"
    

    The returned data is as follows:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    {
      "name": null,
      "response_buffering": true,
      "tags": null,
      "https_redirect_status_code": 426,
      "preserve_host": false,
      "protocols": [
     "http",
     "https"
      ],
      "hosts": [
     "example-service"
      ],
      "service": {
     "id": "977ab5e5-81b6-465f-ae53-68a61413b6ad"
      },
      "headers": null,
      "created_at": 1689914888,
      "updated_at": 1689914888,
      "snis": null,
      "regex_priority": 0,
      "paths": [
     "/api/your-endpoint"
      ],
      "methods": null,
      "sources": null,
      "destinations": null,
      "path_handling": "v0",
      "request_buffering": true,
      "id": "5c967161-2409-46dd-b8f9-822174104f8b",
      "strip_path": true
    }
    
  3. Create a Consumer: Create a consumer entity to represent the end-user or client accessing your API. This can be an individual user or an application.
    1
    2
    3
    
    # Create a consumer
    curl -X POST http://localhost:8001/consumers \
      --data "username=example-user"
    

    The returned data is as follows:

    1
    2
    3
    4
    5
    6
    7
    
    {
      "created_at": 1688718407,
      "custom_id": null,
      "tags": null,
      "id": "2726d40d-5d70-42fe-9316-74fde9c9b42e",
      "username": "example-user"
    }
    
  4. Enable the OAuth 2.0 Plugin: Enable the OAuth 2.0 plugin on the service or route level to secure your API with OAuth 2.0 authentication. Configure the plugin to specify the desired OAuth 2.0 settings, such as enabled grant types, scopes, and other options.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    # Enable the OAuth 2.0 plugin
    curl -X POST http://localhost:8001/services/example-service/plugins \
      --data "name=oauth2" \
      --data "config.enable_client_credentials=true" \
      --data "config.enable_authorization_code=true" \
      --data "config.enable_implicit_grant=true" \
      --data "config.enable_password_grant=true" \
      --data "config.mandatory_scope=true" \
      --data "config.scopes=email"
    

    The returned data is as follows:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    
    {
      "consumer": null,
      "id": "9c160e1d-9047-4fea-ac15-68b1ed88a6a6",
      "config": {
     "mandatory_scope": false,
     "auth_header_name": "authorization",
     "anonymous": null,
     "enable_implicit_grant": true,
     "enable_authorization_code": true,
     "accept_http_if_already_terminated": false,
     "enable_password_grant": true,
     "refresh_token_ttl": 1209600,
     "hide_credentials": false,
     "provision_key": "Acy9zQ7v4KGXPcWA4vLz0uEsJwwE7iZZ",
     "token_expiration": 7200,
     "scopes": [
       "email"
     ],
     "global_credentials": false,
     "reuse_refresh_token": false,
     "pkce": "lax",
     "enable_client_credentials": true
      },
      "protocols": [
     "grpc",
     "grpcs",
     "http",
     "https"
      ],
      "created_at": 1684227513,
      "name": "oauth2",
      "tags": null,
      "route": null,
      "service": {
     "id": "59328986-a83e-4231-9456-505dce8e7ee7"
      },
      "enabled": true
    }
    
  5. Create OAuth 2.0 Credentials: Generate OAuth 2.0 credentials (client ID and client secret) for your consumer. These credentials will be used by the consumer to authenticate and obtain access tokens.
    1
    2
    3
    4
    5
    6
    
    # Create OAuth 2.0 credentials
    curl -k -X POST https://localhost:8443/consumers/example-user/oauth2 \
      --data "name=your-credential-name" \
      --data "client_id=your-client-id" \
      --data "client_secret=your-client-secret" \
      --data "redirect_uris=http://backend-service:5000"
    

    Here, if the client_id and client_secret are specified, Kong will use the provided values. However, if they are not specified, Kong will automatically generate random values for client_id and client_secret.

  6. To obtain an OAuth 2.0 access token, use the following command:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    # Get an OAuth 2.0 access token
    curl -k -X POST https://localhost:8443/api/your-endpoint/oauth2/token \
      --data "grant_type=password" \
      --data "client_id=your-client-id" \
      --data "client_secret=your-client-secret" \
      --data "username=user@example.com" \
      --data "password=your-password" \
      --data "authenticated_userid": "your-authenticated-userid" \
      --data "provision_key": "your-provision-key"
    

    Here, we make a POST request to the token endpoint, specifying the grant type as “password”. Provide the authenticated_userid, provision_key, client ID, client secret, username, and password as parameters to retrieve the access token. authenticated_userid is the value of the return ID in step 3 Create a Consumer, such as “2726d40d-5d70-42fe-9316-74fde9c9b42e”. The returned data is as follows:

    1
    2
    3
    4
    5
    6
    
    {
      "refresh_token": "8BWZ6GY31mqAYJGvnoxp1rIBT9QlBBSz",
      "token_type": "bearer",
      "expires_in": 7200,
      "access_token": "1Go0lynUqrpWwV2mp49L7WGUc8UjvQSU"
    }
    
  7. Include the Access Token: After successfully obtaining an access token, include it in the Authorization header of subsequent API requests as a bearer token. Kong will validate the access token and grant access to the protected API endpoints if it’s valid.
    1
    2
    3
    4
    5
    
    # Get an OAuth 2.0 access token
    curl -X POST http://localhost:8000/api/your-endpoint \
      --header "authorization: bearer your-access-token" \
      --header "content-type: application/json" \
      --data-raw '{"your-key": "your-value"}'
    
  8. If access tokens expire, you can use the refresh token grant type to obtain a new access token without requiring user credentials. If you need to refresh an OAuth 2.0 access token, use the following command:
    1
    2
    3
    4
    5
    6
    
    # Refresh an OAuth 2.0 access token
    curl -k -X POST https://localhost:8433/api/your-endpoint/oauth2/token \
      --data "grant_type=refresh_token" \
      --data "client_id=your-client-id" \
      --data "client_secret=your-client-secret" \
      --data "refresh_token=your-refresh-token"
    

    In this case, we send a POST request to the token endpoint with the grant type set to “refresh_token”. Provide the client ID, client secret, and refresh token as parameters to refresh the access token.

  9. If you want to delete an OAuth 2.0 token, use the following command:
    1
    2
    
    # Delete an OAuth 2.0 token
    curl -X DELETE http://localhost:8001/oauth2_tokens/your-token-id
    

    Make a DELETE request to the endpoint /oauth2_tokens/your-token-id, where your-token-id represents the specific OAuth 2.0 token you wish to delete.

— Fugui,Data engineer、Machine learning Engineer、Software Engineer.