It is important to protect your APIs from unauthorized access. There are a number of ways to do that, including:

  • Validate API keys, as described in the tutorial Part 1: Create a secure API.
  • OAuth and Client Credentials, as described in this tutorial.

This tutorial shows you how to use the Apigee Edge management UI to the secure your API using OAuth access tokens and a type of mechanism for granting access tokens called client credentials. Before we start, here is some background about OAuth, access tokens, client credentials, and the API Platform flow processing model.

OAuth, access tokens, client credentials, and the Platform Flow processing model

OAuth is an authorization protocol that enables apps to access information on behalf of users without requiring users to divulge their username and password.

An access token is a string representing an authorization issued to the client. It is used in OAuth to provide limited access to protected resources. For this reason, OAuth access tokens are often compared to 'valet keys'.

The OAuth 2.0 specification defines different ways of creating access tokens for apps. The various mechanisms for distributing access tokens are referred to as grant types. The most basic grant type defined by OAuth 2.0 is client credentials. In this grant type, OAuth access tokens are generated in exchange for client credentials, which are consumer key-consumer secret pairs.

You configure the client credentials grant type by applying OAuth v2.0 policies to your API and adding conditional Flows that dynamically enforce these policies. The policies protect your API in the following ways:

  • To obtain the access token, the app must first  supply valid customer credentials.
  • Whenever an app makes a call to your API, it must supply a valid access token.
  • API Services validates that the access token presented is valid for the API product, and only then grants access to the protected requested resources.

This tutorial makes use of conditional flows. A conditional flow is a flow whose processing steps are based on a conditional statement, such as the content type specified in the HTTP request header is "text/xml". If the statement is true, the processing step specified in the flow is implemented — for example, a policy is enforced or the message is routed to a specified endpoint. If the conditional statement is not true, the processing step is not implemented. In this way, you can add dynamic behavior to your API proxy. For more information on conditional Flows, see Flow variables and conditions. For basic information about flows and endpoints, see Understanding APIs and API proxies.

What you’ll do in this tutorial

This tutorial shows you how to configure OAuth 2.0 client credentials using the Apigee Edge management UI*. This tutorial implements what is sometime called "two legged" OAuth.

(* You can also do this by directly calling the Apigee management API, as described in OAuth.)

Prerequisites

This tutorial builds on previous tutorials and uses an API proxy for the Yahoo! Weather API as a basis of instruction. If you haven’t already done so, please review the tutorial Part 1: Create a secure API, especially the section "The Relationship between organizations, API Products, apps, and API Keys".

When you log in to Apigee Edge for the first time at https://enterprise.apigee.com, you will see the predefined resources used in this tutorial, including:

  • weatherapi - an API Proxy that you use to access the Yahoo! Weather API.
  • oauth - an API Proxy that you use to generate an access token from customer credentials.
  • Premium Weather API - a product definition.
  • Nikolai Tesla - a developer.
  • Weather App - a developer app.

The oauth API proxy provides free, out-of-the-box OAuth token endpoints that support the client credentials grant type. Each organization (even a free trial org) on Apigee Edge is provisioned with the oauth access token token endpoint. You can begin using the token endpoint as soon as you create an account on Apigee Edge.

The default oauth API Proxy exposes the following endpoint URLs:

https://{org-name}-{env}.apigee.net/oauth/client_credential/accesstoken
https://{org-name}-{env}.apigee.net/oauth/client_credential/refresh_accesstoken

Note: Refreshing access tokens is not supported with two-legged OAuth, so it is not used in this tutorial. However, the policy and conditional flow are described.

Publish these URLs to developers who need to obtain access tokens. App developers configure their apps to call the first endpoint, presenting their consumer key and secret pairs to obtain access tokens. Call the second endpoint to refresh an expired access token.

Step 1: Deploy the API Proxies

This tutorial predefines the weatherapi and oauth proxies for you. However, you must deploy these API Proxies.

  1. Login to https://enterprise.apigee.com.
  2. In the management UI, select the APIs tab.
  3. On the API Proxies page, select oauth.
  4. Select the Deployment button, and then select test from the dropdown menu. The API proxy will be deployed to the test environment.
  5. Select Deploy in the pop up window to deploy the API proxy.
  6. In the management UI, select the APIs tab.
  7. On the API Proxies page, select weatherapi.
  8. Select the Deployment button, and then select test from the dropdown menu. The API proxy will be deployed to the test environment.
  9. Select Deploy in the pop up window to deploy the API proxy.

Step 2: Examine the policies in the OAuth token endpoint

The oauth token endpoint defines two policies and two conditional flows that control the generation of access tokens. Examine these policies and flows before generating a token.

  1. Open the API Proxy Editor by clicking the Develop button in the details page for the oauth API proxy.

    Notice that two policies have been added to your API proxy’s request message flow:

    Policy Name Policy Type     Description
    GenerateAccessTokenClient Oauth v2.0 Generates an access token from a customer key and customer secret. The access token has a duration of one hour.
    RefreshAccessToken Oauth v2.0 Refreshes an expired access token (three-legged OAuth only).

    Also notice that two conditional flows have been added:

    Flow Name Description
    AccessTokenClientCredential The flow that implements the GenerateAccessTokenClient policy.
    RefreshAccessToken The flow that implements the RefreshAccessToken policy (three-legged OAuth only.

The GenerateAccessTokenClient Policy

The GenerateAccessTokenClient policy is a policy of type OAuth v2.0 that generates an access token from a customer key and customer secret. You can view the XML for the policy in the Code view of the API Proxy Editor. You can also view the values for the policy’s XML elements and attributes in the Property Inspector.

The XML for the policy should look like this:

<OAuthV2 name="GenerateAccessTokenClient">
  <!-- This policy generates an OAuth 2.0 access token 
       using the client_credentials grant type -->
  <Operation>GenerateAccessToken</Operation>
  <!-- This is in millseconds, so expire in an hour -->
  <ExpiresIn>3600000</ExpiresIn>
  <SupportedGrantTypes>
    <!-- This part is very important: most real OAuth 2.0 apps will want to use other
         grant types. In this case it is important to NOT include the "client_credentials"
         type because it allows a client to get access to a token with 
         no user authentication -->
      <GrantType>client_credentials</GrantType>
  </SupportedGrantTypes>
  <GrantType>request.queryparam.grant_type</GrantType>
  <GenerateResponse/>
</OAuthV2>

Where:

Policy setting value Description
<Operation>GenerateAccessToken</Operation> The operation to be executed by the OAuth v2.0 policy. By specifying GenerateAccessToken, you configure the policy to generate access tokens for apps.
<ExpiresIn>3600000</ExpiresIn> Specifies the time in milliseconds for which access tokens are valid. In this case, the value specifies 3600000 milliseconds, which means a generated access token is valid for one hour.
<SupportedGrantTypes>
  <GrantType>client_credentials</GrantType>
</SupportedGrantTypes>
Defines the grant types that this token endpoint supports. A token endpoint can be configured to support more than one grant type. For a list of supported grant types, see Authorize requests using OAuth 2.0.
<GrantType>request.queryparam.grant_type
</GrantType>
Specifies the location in the request message where the app indicates the desired grant type. The location can be the HTTP header, a query parameter, or a form parameter. The value request.queryparam.grant_type specifies that the desired grant type is specified in a query parameter named grant_type.

The RefreshAccessToken Policy

The RefreshAccessToken policy is a policy of type OAuth v2.0 that refreshes an expired access token for three-legged OAuth.

The XML for the policy should look like this:
<OAuthV2 name="RefreshAccessToken">
    <Operation>RefreshAccessToken</Operation>
    <!-- This is in millseconds, so expire in half an hour -->
    <ExpiresIn>1800000</ExpiresIn>
    <GrantType>request.queryparam.grant_type</GrantType>
    <GenerateResponse/>
</OAuthV2>

The AccessTokenClientCredential flow

The AccessTokenClientCredential conditional flow enforces the GenerateAccessTokenClient policy when a POST request URI ends with /accesstoken.

The XML for the flow looks like this:

<Flow name="AccessTokenClientCredential">
    <Description/>
    <Request>
    <Step>
    <FaultRules/>
    <Name>GenerateAccessTokenClient</Name>
    </Step>
    </Request>
    <Response/>
    <Condition>(proxy.pathsuffix MatchesPath &quot;/accesstoken&quot;) 
       and (request.verb = &quot;POST&quot;)</Condition>
</Flow>

The condition proxy.pathsuffix MatchesPath &quot;/accesstoken&quot;) and (request.verb = &quot;POST&quot; specifies the following:

  • a variable - proxy.pathsuffix
    Apigee Edge sets the proxy.pathsuffix variable with the fragment of a request URI that follows the URI base path.
  • an operator - MatchesPath
  • a value - &quot;/accesstoken&quot;) and (request.verb = &quot;POST&quot;

    Note: value uses the HTML @quot code for " (double quote character). You do not have to use the HTML code, but can insert " directly.

How it works at runtime
To request an access token, an app makes the following POST request:
http(s)://{org}-{env}.apigee.net/{base_path}/accesstoken?grant_type=client_credentials
where:
  • {org} is your organization
  • {env} is the environment
  • accesstoken is the fragment of the URI that follows the URI base path in these access token requests
  • grant_type specifies the grant type of the access token

When the value of proxy.pathsuffix matches /accesstoken for a POST request, the GenerateAccessTokenClient policy is applied. (Because the proxy.pathsuffix value for all requests to obtain an access token is /accesstoken, the GenerateAccessTokenClient policy is applied for all requests.)

The RefreshAccessToken flow

The RefreshAccesslToken flow enforces the RefreshAccessToken policy when a POST request URI ends with /refresh_accesstoken for three-legged OAuth.

The XML for the flow looks like this:

<Flow name="RefreshAccessToken">
    <Description/>
    <Request>
    <Step>
    <FaultRules/>
    <Name>RefreshAccessToken</Name>
    </Step>
    </Request>
    <Response/>
    <Condition>(proxy.pathsuffix MatchesPath &quot;/refresh_accesstoken&quot;) 
        and (request.verb = &quot;POST&quot;)</Condition>
</Flow>

Step 3: Apply policies to protected resources

Authorization is enforced at runtime by verifying access tokens. To do so, apply an OAuth v2.0 policy to the weatherapi API Proxy. This policy verifies the access token passed in the request is valid.

  1. In the management UI, select the APIs tab.
  2. On the API Proxies page, select weatherapi.
  3. Click the Development button to open the Proxy Editor.
  4. In the API Proxy Editor, click New Policy.
  5. Select OAuth v2.0 in the Security category.
  6. Change the name in the New Policy dialog to ValidateOAuth and uncheck the Attach Policy checkbox.

  7. Click Add.
    The ValidateOAuth policy is added to the list of policies in the Navigator view.

  8. In the Code view of your ValidateOAuth policy, remove the <GenerateResponse> element, and leave the other elements as is.
    For the ValidateOAuth policy you do want the request to be forwarded to the target endpoint.

    After you remove the <GenerateResponse> element, the XML for the policy should look like this:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <OAuthV2 async="false" continueOnError="false" enabled="true" name="ValidateOAuth">
        <DisplayName>ValidateOAuth</DisplayName>
        <FaultRules/>
        <Properties/>
        <Attributes/>
        <ExternalAuthorization>false</ExternalAuthorization>
        <Operation>VerifyAccessToken</Operation>
        <SupportedGrantTypes/>
        <Tokens/>
    </OAuthV2>    
    
  9. Click the Save button in the API Proxy Editor.
    The current revision is saved and redeployed to your test environment.

Step 4: Attach the policy to the proxy endpoint

Now that you have defined a policy to verify an access token at runtime, you create a conditional flow to apply the policy to the protected resource.

  1. In the API Proxy Editor, click New, then New Conditional Flow.
  2. In the New Policy dialog, enter the following values:
    • Flow Name: Authorize
    • Condition: proxy.pathsuffix MatchesPath "/forecastrss"
    • Add to Endpoint: Proxy Endpoint Default
  3. Click Add.
    The Authorize conditional flow is added to the list of flows for the proxy endpoint named 'default' in the Navigator view.

  4. In the Code view, update the XML for the the Authorize conditional flow to set the <Request> tag as follows:
    <Request>
        <Step>
            <Name>validateoauth</Name>
        </Step>
    </Request>
    
  5. Click the Save button in the API Proxy Editor to save the current revision with your changes and to redeploy it to your test environment.

    Now, when a request comes in to an endpoint in the form:
    http(s)://{org}-{env}.apigee.net/v0/weather/forecastress?w=12797282
    
    This conditional flow applies the ValidateOAuth policy because the URL ends with /forecastrss.

Step 5: Test the OAuth v2.0 policies

Test that the OAuth v2.0 policies are working correctly by making a call to the weatherapi API Proxy with a valid access token.

An app obtains an access token by making a request to the token endpoint with valid credentials (consumer key and consumer secret), so you need to obtain the credentials for your app (weatherapp) first.

Step 5-1: Retrieve the app credentials

As an admin for your organization, you can retrieve the credentials for an app using the API Platform UI.

  1. In the management UI, click the Publish tab, then Developer Apps.
  2. On the Developer Apps page, select Weather App.
    This displays the details page for the app. The credentials are in the Consumer Key and Consumer Secret columns for the associated API product (Premium Weather API) when you click the Show button. 

Step 5-2: Get the access token

Get the access token by directly calling the API Platform API. Use the cURL tool to issue the following request to the API Platform API:

$ curl https://{org}-test.apigee.net/oauth/client_credential/
  accesstoken?grant_type=client_credentials -X POST -d 
  'client_id={consumer_key}&client_secret={consumer_secret}'

Replace:

  • {org} with your organization name -- typically the API project name you provided when you signed up for an Apigee account.
  • {consumer_key} with the consumer key you retrieved in the preceding step.
  • {consumer_secret} with the consumer secret you retrieved in the preceding step.

For example:

$ curl https://myorg-test.apigee.net/oauth/client_credential
  /accesstoken?grant_type=client_credentials -X POST -d 
  'client_id=SJOaCEGohSu3vpNswMs5YdBlc2GOAh1J&client_secret=FaXZNVQfLQBrCqfd'

You should receive a response similar to this (notice the access token in the response):

{
  "issued_at" : "1382703699776",
  "application_name" : "8586c7b7-2936-4779-b7a6-97014e436d7d",
  "scope" : "READ",
  "status" : "approved",
  "api_product_list" : "[PremiumWeatherAPI]",
  "expires_in" : "3599",
  "developer.email" : "tesla@weathersample.com",
  "organization_id" : "0",
  "client_id" : "SJOaCEGohSu3vpNswMs5YdBlc2GOAh1J",
  "access_token" : "UAj2yiGAcMZGxfN2DhcUbl9v8WsR",
  "organization_name" : "myorg",
  "refresh_token_expires_in" : "0",
  "refresh_count" : "0"
}

Note the access_token field that contains the new access token.

Step 5-3: Call your API

Call the weatherapi proxy for the Yahoo! Weather API. That proxy includes a resource named forecast weather. The resource path is /forecastrss.

To get Yahoo! weather data through your API proxy, apps need to access that resource. To do that, specify an HTTP GET request to the URL:

http://{org}-test.apigee.net/v0/weather/forecastrss?w=12797282

Apps also need to provide a valid access token in the request.

Use cURL to issue a call to the resource and supply the access token in the header. For example:

$ curl -H "Authorization: Bearer UAj2yiGAcMZGxfN2DhcUbl9v8WsR" 
  http://myorg-test.apigee.net/v0/weather/forecastrss?w=12797282 

You should receive the following data in response:

{
   "rss":{
      "#namespaces":{
         "yweather":"http:\/\/xml.weather.yahoo.com\/ns\/rss\/1.0",
         "geo":"http:\/\/www.w3.org\/2003\/01\/geo\/wgs84_pos#"
      },
      "#attrs":{
         "@version":"2.0"
      },
      "channel":{
         "title":"Yahoo! Weather - Palo Alto, CA",
         "link":"http:\/\/us.rd.yahoo.com\/dailynews\/rss\/weather\/Palo_Alto__CA\/*http:\/\/weather.yahoo.com\/forecast\/USCA1093_f.html",
         "description":"Yahoo! Weather for Palo Alto, CA",
         "language":"en-us",
         "lastBuildDate":"Mon, 09 Dec 2013 1:46 pm PST",
         "ttl":"60",
         "yweather:location":{
            "#attrs":{
               "@city":"Palo Alto",
               "@region":"CA",
               "@country":"United States"
            }
         }, ...

Notice that the data is in JSON format. The weatherapi proxy implements an XML to JSON transform policy on the response PreFlow from the backend server.

If you don’t provide a valid access token in the request (or provide no access token), you get a failure message. For example, if you make the following request (note the invalid access token b8dAcCEsST0ken123):

$ curl -H "Authorization: Bearer b8dAcCEsST0ken123"
  http://{org}-test.apigee.net/v1/weather/forecastrss?w=12797282 

You get the following error:

{"fault":{"faultstring":"Invalid Access Token","detail":{"errorcode":"keymanagement.service.invalid_access_token"}}}

Note: Remember that when you added the GenerateAccessToken policy in Step 2: Examine the policies in the OAuth token endpoint, you set an expiration value of 3600000 milliseconds (1 hour) in the <ExpiresIn> element. So if you wait longer than an hour between requesting an access token and submitting a call to your API, the access token will expire. If you submit the request with the expired access token, you get the following error:

{"fault":{"faultstring":"Access Token expired","detail":{"errorcode":"keymanagement.service.access_token_expired"}}}

You’ll then have to request another access token.

Learn more

Help or comments?

  • Something's not working: See Apigee Support
  • Something's wrong with the docs: Click Send Feedback in the lower right.
    (Incorrect? Unclear? Broken link? Typo?)