Skip navigation

Securing public access

When using the public Delivery API, you cannot use it to manage the user roles and their access to particular content in your application. With secure access enabled, you can protect your content by requiring an API key with each request and configuring content authorization in your app.

Premium feature

Secure access to the Delivery API requires a Professional plan or higher.

Table of contents

    Secure access to the Delivery API allows you to use two concurrent API keys, Primary and Secondary.

    Note: For continuous use, we recommend using the Primary key to authenticate your API requests and only using the Secondary key when revoking the Primary key to prevent your site from any downtime. For more information, see the Revoking the API keys section of this tutorial.

    Primary vs. Secondary key

    The following instructions work equally for both the Primary key and the Secondary key.

    Enabling secure access

    Secure access to the Delivery API is disabled by default for new projects and you need to activate it. By activating the secure access, the system will also generate new API keys, Primary and Secondary.

    1. In Kentico Kontent, choose a project.
    2. From the app menu, choose .
    3. Under Development, choose API keys.
    4. In the Secure access box, toggle the Inactive switch to activate secure access.
    A screenshot of secure access enabled in a project.

    You will mainly use the Primary key to authenticate your requests. Both API keys are generated per project and have no expiration date. For more information, see secure access in our API reference.

    Getting your API key

    Every request to the Delivery API with secure access enabled must be authenticated with an API key. This key is unique to each project in Kentico Kontent.

    To get the key:

    1. In Kentico Kontent, choose a project.
    2. From the app menu, choose .
    3. Under Development, choose API keys.
    4. In the Secure access box, click .

    You can now use the key to authenticate your requests to the API.

    Authenticating requests

    Every request you make must come with an API key in the Authorization header. The Authorization header uses the following format: Authorization: Bearer <YOUR_API_KEY>

    Retrieving secured content

    Security tips

    Here are some quick tips to help you while using the secure access to the Delivery API:

    • Only regenerate one key at a time to prevent downtime.
    • Do not store API Keys in the source code.
    • Encrypt the key when storing it.
    • Regenerate your API keys periodically.
    • The older a key is, the higher the probability it could have been compromised.

    To retrieve a specific content item from Kentico Kontent via API, you need to use the project ID and the content item's codename in your request. See Getting content to find out how you can get these two values.

    The Delivery API uses the following URI to retrieve the published content:

    https://deliver.kontent.ai/<YOUR_PROJECT_ID>/

    Once you have the project ID and content item codename, you can retrieve the published content item.

    For example, to retrieve the content of a published article named "On Roasts" from the sample project, you can use the following request.

    • Java
    // Tip: Find more about Java/JavaRx SDKs at https://docs.kontent.ai/javaandroid import com.kenticocloud.delivery_core.*; import com.kenticocloud.delivery_rx.*; import io.reactivex.Observer; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; // Prepares the DeliveryService configuration object String projectId = "975bf280-fd91-488c-994c-2f04416e5ee3"; String secureApiKey = "<YOUR_API_KEY>"; IDeliveryConfig config = DeliveryConfig.newConfig(projectId) .withSecuredApiKey(secureApiKey); // Gets the latest version of a content item using a simple request ContentItem item = deliveryService.<ContentItem>item("on_roasts") .get() .getItem(); // Gets the latest version of a content item using RxJava2 deliveryService.<ContentItem>item("on_roasts") .getObservable() .subscribe(new Observer<DeliveryItemResponse<ContentItem>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(DeliveryItemResponse<ContentItem> response) { // Gets the content item ContentItem item = response.getItem(); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
    // Tip: Find more about Java/JavaRx SDKs at https://docs.kontent.ai/javaandroid import com.kenticocloud.delivery_core.*; import com.kenticocloud.delivery_rx.*; import io.reactivex.Observer; import io.reactivex.disposables.Disposable; import io.reactivex.functions.Function; // Prepares the DeliveryService configuration object String projectId = "975bf280-fd91-488c-994c-2f04416e5ee3"; String secureApiKey = "<YOUR_API_KEY>"; IDeliveryConfig config = DeliveryConfig.newConfig(projectId) .withSecuredApiKey(secureApiKey); // Gets the latest version of a content item using a simple request ContentItem item = deliveryService.<ContentItem>item("on_roasts") .get() .getItem(); // Gets the latest version of a content item using RxJava2 deliveryService.<ContentItem>item("on_roasts") .getObservable() .subscribe(new Observer<DeliveryItemResponse<ContentItem>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(DeliveryItemResponse<ContentItem> response) { // Gets the content item ContentItem item = response.getItem(); } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
    • Swift
    // Tip: Find more about Swift SDK at https://docs.kontent.ai/ios import KenticoCloud let client = DeliveryClient.init(projectId: "975bf280-fd91-488c-994c-2f04416e5ee3", secureApiKey: "<YOUR_API_KEY>") // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models client.getItem(modelType: Article.self, itemName: "on_roasts") { (isSuccess, deliveryItem, error) in if isSuccess { if let article = deliveryItem.item { // Use your item here } } else { if let error = error { print(error) } }
    // Tip: Find more about Swift SDK at https://docs.kontent.ai/ios import KenticoCloud let client = DeliveryClient.init(projectId: "975bf280-fd91-488c-994c-2f04416e5ee3", secureApiKey: "<YOUR_API_KEY>") // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models client.getItem(modelType: Article.self, itemName: "on_roasts") { (isSuccess, deliveryItem, error) in if isSuccess { if let article = deliveryItem.item { // Use your item here } } else { if let error = error { print(error) } }
    • Java
    // Tip: Find more about Java/JavaRx SDKs at https://docs.kontent.ai/java import com.github.kentico.kontent.delivery; DeliveryOptions options = new DeliveryOptions(); options.setProjectId("975bf280-fd91-488c-994c-2f04416e5ee3"); options.setProductionApiKey("<YOUR_API_KEY>"); DeliveryClient client = new DeliveryClient(options); ContentItemResponse item = client.getItem("on_roasts");
    // Tip: Find more about Java/JavaRx SDKs at https://docs.kontent.ai/java import com.github.kentico.kontent.delivery; DeliveryOptions options = new DeliveryOptions(); options.setProjectId("975bf280-fd91-488c-994c-2f04416e5ee3"); options.setProductionApiKey("<YOUR_API_KEY>"); DeliveryClient client = new DeliveryClient(options); ContentItemResponse item = client.getItem("on_roasts");
    • JavaScript
    // Tip: Find more about JS/TS SDKs at https://docs.kontent.ai/javascript const KontentDelivery = require('@kentico/kontent-delivery'); // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models class Article extends KontentDelivery.ContentItem { constructor() { super(); } } const deliveryClient = new KontentDelivery.DeliveryClient({ projectId: '975bf280-fd91-488c-994c-2f04416e5ee3', globalQueryConfig: { useSecuredMode: true, // Queries the Delivery API using secure access. }, secureApiKey: '<YOUR_API_KEY>', typeResolvers: [ new KontentDelivery.TypeResolver('article', (rawData) => new Article) ] }); deliveryClient.item('on_roasts') .toObservable() .subscribe(response => console.log(response));
    // Tip: Find more about JS/TS SDKs at https://docs.kontent.ai/javascript const KontentDelivery = require('@kentico/kontent-delivery'); // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models class Article extends KontentDelivery.ContentItem { constructor() { super(); } } const deliveryClient = new KontentDelivery.DeliveryClient({ projectId: '975bf280-fd91-488c-994c-2f04416e5ee3', globalQueryConfig: { useSecuredMode: true, // Queries the Delivery API using secure access. }, secureApiKey: '<YOUR_API_KEY>', typeResolvers: [ new KontentDelivery.TypeResolver('article', (rawData) => new Article) ] }); deliveryClient.item('on_roasts') .toObservable() .subscribe(response => console.log(response));
    • C#
    // Tip: Find more about .NET SDKs at https://docs.kontent.ai/net using Kentico.Kontent.Delivery; // Initializes a secured content delivery client IDeliveryClient client = DeliveryClientBuilder .WithOptions(builder => builder .WithProjectId("975bf280-fd91-488c-994c-2f04416e5ee3") .UseSecuredProductionApi("<YOUR_API_KEY>") .Build()) .Build(); // Gets a specific content item // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models DeliveryItemResponse response = await client.GetItemAsync("on_roasts"); IReadOnlyList<ContentItem> items = response.Items;
    // Tip: Find more about .NET SDKs at https://docs.kontent.ai/net using Kentico.Kontent.Delivery; // Initializes a secured content delivery client IDeliveryClient client = DeliveryClientBuilder .WithOptions(builder => builder .WithProjectId("975bf280-fd91-488c-994c-2f04416e5ee3") .UseSecuredProductionApi("<YOUR_API_KEY>") .Build()) .Build(); // Gets a specific content item // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models DeliveryItemResponse response = await client.GetItemAsync("on_roasts"); IReadOnlyList<ContentItem> items = response.Items;
    • PHP
    <?php // Tip: Find more about PHP SDKs at https://docs.kontent.ai/php // Defined by Composer to include required libraries require __DIR__ . '/vendor/autoload.php'; use Kentico\Kontent\Delivery\DeliveryClient; $client = new DeliveryClient('975bf280-fd91-488c-994c-2f04416e5ee3', '<YOUR_API_KEY>'); $item = $client->getItem('on_roasts');
    <?php // Tip: Find more about PHP SDKs at https://docs.kontent.ai/php // Defined by Composer to include required libraries require __DIR__ . '/vendor/autoload.php'; use Kentico\Kontent\Delivery\DeliveryClient; $client = new DeliveryClient('975bf280-fd91-488c-994c-2f04416e5ee3', '<YOUR_API_KEY>'); $item = $client->getItem('on_roasts');
    • cURL
    curl --request GET \ --url https://deliver.kontent.ai/975bf280-fd91-488c-994c-2f04416e5ee3/items/on_roasts \ --header 'authorization: Bearer <YOUR_API_KEY>'
    curl --request GET \ --url https://deliver.kontent.ai/975bf280-fd91-488c-994c-2f04416e5ee3/items/on_roasts \ --header 'authorization: Bearer <YOUR_API_KEY>'
    • Ruby
    # Tip: Find more about Ruby SDKs at https://docs.kontent.ai/ruby require 'delivery-sdk-ruby' delivery_client = Kentico::Kontent::Delivery::DeliveryClient.new project_id: '975bf280-fd91-488c-994c-2f04416e5ee3', secure_key: '<YOUR_API_KEY>' delivery_client.item('on_roasts').execute do |response| item = response.item end
    # Tip: Find more about Ruby SDKs at https://docs.kontent.ai/ruby require 'delivery-sdk-ruby' delivery_client = Kentico::Kontent::Delivery::DeliveryClient.new project_id: '975bf280-fd91-488c-994c-2f04416e5ee3', secure_key: '<YOUR_API_KEY>' delivery_client.item('on_roasts').execute do |response| item = response.item end
    • TypeScript
    // Tip: Find more about JS/TS SDKs at https://docs.kontent.ai/javascript import { ContentItem, DeliveryClient, Elements, TypeResolver } from '@kentico/kontent-delivery'; // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models export class Article extends ContentItem { public title: Elements.TextElement; public summary: Elements.TextElement; public post_date: Elements.DateTimeElement; public teaser_image: Elements.AssetsElement; public related_articles: Article[]; } const deliveryClient = new DeliveryClient({ projectId: '975bf280-fd91-488c-994c-2f04416e5ee3', globalQueryConfig: { useSecuredMode: true // Queries the Delivery API using secure access. }, secureApiKey: '<YOUR_API_KEY>', typeResolvers: [new TypeResolver('article', (rawData) => new Article())] }); deliveryClient .item<Article>('on_roasts') .toObservable() .subscribe(response => console.log(response));
    // Tip: Find more about JS/TS SDKs at https://docs.kontent.ai/javascript import { ContentItem, DeliveryClient, Elements, TypeResolver } from '@kentico/kontent-delivery'; // Create strongly typed models according to https://docs.kontent.ai/strongly-typed-models export class Article extends ContentItem { public title: Elements.TextElement; public summary: Elements.TextElement; public post_date: Elements.DateTimeElement; public teaser_image: Elements.AssetsElement; public related_articles: Article[]; } const deliveryClient = new DeliveryClient({ projectId: '975bf280-fd91-488c-994c-2f04416e5ee3', globalQueryConfig: { useSecuredMode: true // Queries the Delivery API using secure access. }, secureApiKey: '<YOUR_API_KEY>', typeResolvers: [new TypeResolver('article', (rawData) => new Article())] }); deliveryClient .item<Article>('on_roasts') .toObservable() .subscribe(response => console.log(response));

    After performing the request, you receive a single content item in the JSON format.

    • JSON
    { "item": { "system": { "id": "f4b3fc05-e988-4dae-9ac1-a94aba566474", "name": "On Roasts", "codename": "on_roasts", "language": "en-US", "type": "article", "sitemap_locations": [ "articles" ], "last_modified": "2017-11-02T09:11:00.1067922Z" }, "elements": { "personas": { "type": "taxonomy", "name": "Personas", "taxonomy_group": "personas", "value": [ { "name": "Barista", "codename": "barista" }, { "name": "Coffee blogger", "codename": "coffee_blogger" } ] }, "title": { "type": "text", "name": "Title", "value": "On roasts" }, "teaser_image": { "type": "asset", "name": "Teaser image", "value": [ { "name": "on-roasts-1080px.jpg", "type": "image/jpeg", "size": 121946, "description": "Coffee Roastery", "url": "https://assets-us-01.kc-usercontent.com/e1a09831-6a84-4f18-89da-7199f37ee3e3/f6daed1f-3f3b-4036-a9c7-9519359b9601/on-roasts-1080px.jpg" } ] }, "post_date": { "type": "date_time", "name": "Post date", "value": "2014-11-07T00:00:00Z" }, "summary": { "type": "text", "name": "Summary", "value": "Roasting coffee beans can take from 6 to 13 minutes. Different roasting times produce different types of coffee, with varying concentration of caffeine and intensity of the original flavor." }, "body_copy": { "type": "rich_text", "name": "Body Copy", "images": {}, "links": {}, "modular_content": [], "value": "<p>There’s nothing complicated about roasting. It’s as easy as baking a pie, maybe even simpler as there’s just one ingredient. What’s complicated is fine-tuning the whole process to perfection. ...</p>" }, "related_articles": { "type": "modular_content", "name": "Related articles", "value": [ "coffee_processing_techniques", "origins_of_arabica_bourbon" ] }, "meta_keywords": { "type": "text", "name": "Meta keywords", "value": "roasts, coffee" }, "meta_description": { "type": "text", "name": "Meta description", "value": "Roasting coffee beans can take from 6 to 13 minutes. Different roasting times produce different types of coffee." }, "url_pattern": { "type": "url_slug", "name": "URL pattern", "value": "on-roasts" }, ... } }, "modular_content": { ... } }
    { "item": { "system": { "id": "f4b3fc05-e988-4dae-9ac1-a94aba566474", "name": "On Roasts", "codename": "on_roasts", "language": "en-US", "type": "article", "sitemap_locations": [ "articles" ], "last_modified": "2017-11-02T09:11:00.1067922Z" }, "elements": { "personas": { "type": "taxonomy", "name": "Personas", "taxonomy_group": "personas", "value": [ { "name": "Barista", "codename": "barista" }, { "name": "Coffee blogger", "codename": "coffee_blogger" } ] }, "title": { "type": "text", "name": "Title", "value": "On roasts" }, "teaser_image": { "type": "asset", "name": "Teaser image", "value": [ { "name": "on-roasts-1080px.jpg", "type": "image/jpeg", "size": 121946, "description": "Coffee Roastery", "url": "https://assets-us-01.kc-usercontent.com/e1a09831-6a84-4f18-89da-7199f37ee3e3/f6daed1f-3f3b-4036-a9c7-9519359b9601/on-roasts-1080px.jpg" } ] }, "post_date": { "type": "date_time", "name": "Post date", "value": "2014-11-07T00:00:00Z" }, "summary": { "type": "text", "name": "Summary", "value": "Roasting coffee beans can take from 6 to 13 minutes. Different roasting times produce different types of coffee, with varying concentration of caffeine and intensity of the original flavor." }, "body_copy": { "type": "rich_text", "name": "Body Copy", "images": {}, "links": {}, "modular_content": [], "value": "<p>There’s nothing complicated about roasting. It’s as easy as baking a pie, maybe even simpler as there’s just one ingredient. What’s complicated is fine-tuning the whole process to perfection. ...</p>" }, "related_articles": { "type": "modular_content", "name": "Related articles", "value": [ "coffee_processing_techniques", "origins_of_arabica_bourbon" ] }, "meta_keywords": { "type": "text", "name": "Meta keywords", "value": "roasts, coffee" }, "meta_description": { "type": "text", "name": "Meta description", "value": "Roasting coffee beans can take from 6 to 13 minutes. Different roasting times produce different types of coffee." }, "url_pattern": { "type": "url_slug", "name": "URL pattern", "value": "on-roasts" }, ... } }, "modular_content": { ... } }

    Note: Modular content (content linked using Rich text or Linked items elements) was omitted from the response for brevity.

    You can limit the retrieved data, for example, retrieve only specific elements, by using optional query parameters. See the Delivery API reference to learn more about the available options and methods.

    Revoking the API keys

    In certain situations, you may need to revoke one of the API keys and generate a new one. For example, when you suspect unauthorized key usage or when a developer with access to the API key has left your company.

    For the reasons above, one or both of the API keys can be regenerated. Activating a new key will immediately replace the old key, making it useless. Requests made with a revoked API Key will then receive a 401 Unauthorized HTTP status code in the response.

    Note: First you need to have the secure access for the Delivery API enabled in the UI.

    1. In Kentico Kontent, choose a project.
    2. From the app menu, choose .
    3. Under Development, choose API keys.
    4. Regenerate the Secondary key as this ensures it's new and secure.
    5. Change all applications using the secured Delivery API to use the newly regenerated Secondary key.
    6. Validate all applications using the Secondary key are functioning correctly.
    7. Regenerate the Primary key to make sure any unauthorized users cannot use this key to access the application.
    8. (Optional) Switch back to using the regenerated Primary key in all of your applications.

    The last step is optional as switching back to the regenerated Primary key might seem unnecessarily complicated. The reason behind this is simple – you can easily keep track of the API key you are currently using for your application. If you only use the Secondary key to prevent downtime when revoking the Primary key, it can keep things simple in the long run.