Was this helpful?

OAuth 2.0 defines an authorization protocol for protected API resources. To ensure that apps are allowed to act on behalf of users, OAuth 2.0 relies on 'access tokens'. To access protected resources, consumer apps must obtain 'access tokens'. The OAuth 2.0 specification defines the various ways that apps can request and use access tokens. Apigee Edge provides a policy type that enables you to configure OAuth 2.0 authorization for your APIs.

For working examples of OAuth 2.0-enabled API proxies, please refer to the API Platform samples available on GitHub. The sample proxies include examples that demonstrate client credentials, authorization code, implicit, and password grant types.

For step-by-step instructions on using the default OAuth 2.0 endpoints provided by Apigee Edge see Secure APIs with OAuth 2.0: client credentials.

Setting up OAuth 2.0 authorization for your API is a three step process:

  1. Configure a token endpoint: An OAuth token endpoint defines a URI on Apigee Edge. The token endpoint is configured with a policy of type OAuthV2. In the OAuthV2 policy, the GenerateAccessToken operation is specified. When this operation is specified, you have the option of configuring one or more grant types. For each grant type specified, an additional set of configuration elements are exposed, providing flexibility in the way that APIs exposed through Apigee Edge manage OAuth-based authorization.
  2. Apply an OAuth validation policy to protected resource URIs: To enforce OAuth at runtime, attach a policy of type OAuthV2 to a Flow that exposes a protected resource. In the OAuthV2 policy, specify the VerifyAccessToken operation.
  3. Configure one or more API products: The VerifyAccessToken operation resolves the access token to an API product for which the app has been approved. The request URI is verified against the list of URIs defined in the API product. If the request URI is included in the list defined by the approved API product, then the request is forwarded to the protected resource.
Default OAuth 2.0 client credentials token and refresh endpoints are provisioned for every organization. Also, a default API product is configured for every API proxy that you create in your organization. See OAuth.

Configuring token endpoints

OAuth 2.0 policies are used both to generate and to validate OAuth 2.0-compliant tokens. To generate tokens on behalf of app end users, OAuth 2.0 policies that specify the GenerateAccessToken operation are attached to a token endpoint.

Deploy a single API proxy to function as a token endpoint for all API proxies in an environment. A single API proxy configured as a token endpoint can support multiple grant types. By setting up a single token endpoint, you can publish a unified set of URIs that app developers can use to obtain tokens.

A token endpoint is simply a URI path that the system uses to identify requests for access tokens. On Apigee Edge, a token endpoint is a conditional Flow to which an OAuthV2 policy is attached. The OAuthV2 policy specifies the GenerateAccessToken operation as an element.

For example, to configure a token endpoint that generates tokens on requests to the URI path /accesstoken:

<Flow name="TokenEndpoint">
  <Condition>proxy.pathsuffix MatchesPath "/accesstoken"</Condition>
  <Request>
    <Step><Name>GenerateAccessToken</Name></Step>
  </Request>
</Flow>

Note that the variable proxy.pathsuffix defines the URI fragment following the base path configured in the ProxyEndpoint. For example, to obtain an OAuth token, an app makes a request to:

http://{org_name}-prod.apigee.net/oauth/accesstoken

In the example URL above, the ProxyEndpoint BasePath is /oauth and suffix is /accesstoken.

The token endpoint URL is provided to your app developers, who invoke this URL in their apps to obtain access tokens at runtime.

Configuring authorization endpoints

Similarly, you can configure authorization endpoints to issue authorization codes. For example:

<Flow name="AuthorizationEndpoint">
  <Condition>proxy.pathsuffix == "/authorize"</Condition>
  <Request>
    <Step><Name>GenerateAuthCode</Name></Step>
  </Request>
</Flow>
Sample Code For a sample API proxy configured for authorization code grant type, see the API Platform samples on GitHub.

For instructions on configuring an API proxy to support authorization code, please see Secure APIs with OAuth 2.0: auth code.

OAuth 2.0 Grant Types

OAuth 2.0 policies generate access tokens using the GrantType method element. Four grant types, specified by OAuth 2.0, are supported:

Grant Type Description
Client credentials "Two-legged" OAuth, usually implemented for trusted clients (for example, apps developed by the API provider themselves).
Authorization code "Three-legged" OAuth, which enables an app end users to obtain an access token without exposing credentials to the app. The app requests an access token using an authorization code returned by the intermediary who authenticates the app end user. API Services can act as both authorization server (generating authorization codes) and as a token endpoint (issuing access tokens in return for valid authorization codes).
Implicit A variation on authorization code, usually enforced for browser-based apps that are implemented in scripting languages such as JavaScript
Resource Owner Password Credentials Used only when apps are trusted. Enables an app end user to obtain an access token in return for a valid username/password credentials. The benefit of password grant type is the one-time use of password credentials to obtain a long-lived access token.

Verifying access tokens

Once a token endpoint is set up for an API proxy, a corresponding OAuthV2 policy that specifies the VerifyAccessToken operation is attached to the Flow that exposes the protected resource.

For example, to ensure that all requests to an API are authorized, the following policy enforces access token verification:

<OAuthV2 name="VerifyOAuthAccessToken">
  <Operation>VerifyAccessToken</Operation>
</OAuthV2>

The policy is attached to the API resource to be protected. To ensure that all requests to an API are verified, attach the policy to the ProxyEndpoint request PreFlow, as follows:

<PreFlow>
  <Request>
	<Step><Name>VerifyOAuthAccessToken</Name></Step>
  </Request>
</PreFlow>

The following optional elements can be used to override the default settings for the VerifyAccessToken operation.

Name Description
Scope

A space separated list of scopes that must be present in the access token for verification to succeed. For example, the following policy will check the access token to ensure that it contains the scopes READ and WRITE:

<OAuthV2 name="ValidateOauthScopePolicy">
  <Operation>VerifyAccessToken</Operation>
  <Scope>READ WRITE</Scope>
</OAuthV2>
AccessToken The variable where the access token is expected to be located. For example request.queryparam.accesstoken. By default, the access token is expected to be presented by the app in the Authorization HTTP header,  according to the OAuth 2.0 specification. Use this setting if the access token is expected to be presented in a non-standard location, such as a query parameter, or an HTTP header with a name other than Authorization.

Grant type policy details

The OAuth 2.0 policy enables the user to specify which API calls to secure with OAuth 2.0. The OAuth policy exposes configuration variables that enable the user to configure the behavior of the policy. Apigee supports the following OAuth policies based on the OAuth 2.0 specification.

Grant Type Policy Format Description Configuration Example
authorization_code Generate Authorization Code Generates an authorization code that can in turn be used to get an access token. Attach the policy at the authorization end point.
<OAuthV2 name="GetAuthCode">
  <Operation>GenerateAuthorizationCode</Operation>
  <ExpiresIn>1000</ExpiresIn>
  <GenerateResponse />
</OAuthV2>
Generate AccessToken Generates an access token in exchange for an authorization code. The access token can be used to gain access to the protected resources (target APIs). Attach the policy at the access token endpoint.
<OAuthV2 name="GenerateAccessToken">
  <Operation>GenerateAccessToken</Operation>
  <ExpiresIn>1000</ExpiresIn>
  <GenerateResponse />
  <SupportedGrantTypes>
   <GrantType>authorization_code</GrantType>
  </SupportedGrantTypes>
  <GrantType>request.queryparam.grant_type</GrantType>
  <Code>request.queryparam.code</Code>
  <ClientId>request.queryparam.client_id</ClientId>
  <RedirectUri>request.queryparam.redirect_uri</RedirectUri>
  <Scope>request.queryparam.scope</Scope>
</OAuthV2>
Refresh AccessToken Token used to re-issue the access token post expiry. Attach the policy at the refresh token end point.
<OAuthV2 name="RefreshAccessToken">
  <Operation>RefreshAccessToken</Operation>
  <ExpiresIn>1000</ExpiresIn>
  <GenerateResponse />
  <GrantType>request.queryparam.grant_type</GrantType>
</OAuthV2>
implicit GenerateImplicit AccessToken Attach the policy at the access token endpoint.
<OAuthV2 name="GenerateAccessTokenImplicit">
  <Operation>GenerateAccessTokenImplicitGrant</Operation>
  <ExpiresIn>1000</ExpiresIn>
  <GenerateResponse />
  <ResponseType>request.queryparam.response_type</ResponseType> 
  <ClientId>request.queryparam.client_id</ClientId> 
  <RedirectUri>request.queryparam.redirect_uri</RedirectUri>  
  <Scope>request.queryparam.scope</Scope>  
  <State>request.queryparam.state</State> 
  <AppEndUser>request.queryparam.app_enduser</AppEndUser> 
</OAuthV2>
password Generate AccessToken Attach the policy at the access token endpoint.
<OAuthV2 name="GenerateAccessToken">
  <Operation>GenerateAccessToken</Operation>
  <ExpiresIn>1000</ExpiresIn>
  <GenerateResponse />
  <SupportedGrantTypes>
    <GrantType>password</GrantType>
  </SupportedGrantTypes>
  <GrantType>request.queryparam.grant_type</GrantType> 
  <ClientId>request.queryparam.client_id</ClientId>    
  <Scope>request.queryparam.scope</Scope>
  <AppEndUser>request.queryparam.app_enduser</AppEndUser>  
  <UserName>request.queryparam.user_name</UserName>
  <PassWord>request.queryparam.password</PassWord> 
</OAuthV2>
Refresh AccessToken Attach the policy at the refresh token end point.
<OAuthV2 name="RefreshAccessToken">
  <Operation>RefreshAccessToken</Operation>
  <ExpiresIn>1000</ExpiresIn>
  <GenerateResponse />
  <GrantType>request.queryparam.grant_type</GrantType>
</OAuthV2>
client_credentials Generate AccessToken Attach the policy at the access token end point.
<OAuthV2 name="GenerateAccessToken">
  <Operation>GenerateAccessToken
  </Operation>
  <ExpiresIn>1000</ExpiresIn>
  <GenerateResponse />
  <SupportedGrantTypes>
    <GrantType>client_credentials</GrantType>
  </SupportedGrantTypes>
  <GrantType>request.queryparam.grant_type</GrantType>
</OAuthV2>

Note: The ExpiresIn element (optional) enforces the expiry time of the authorization code in milliseconds. The expiry time of authorization code is system generated plus ExpiresIn value. If ExpiresIn is set to -1, the system considers it as a infinite life time. If ExpiresIn is not specified, the system applies a default value configured at the system level. Contact Apigee Support for more information about default system settings.

OAuth 2.0 policy settings reference

Name Description Valid Values Related Operation and Grant Type combinations
name The name of the policy. Must be unique within the API proxy configuration Any string, special characters not supported. All
Operation The OAuth 2.0 operation implemented by the policy
  • GenerateAccessToken
  • GenerateAccessTokenImplicitGrant
  • GenerateAuthorizationCode
  • RefreshAccessToken
  • VerifyAccessToken
All
ExpiresIn ExpiresIn (optional) enforces the expiry time of the authorization code in milliseconds. The expiry time of authorization code is system generated plus ExpiresIn value. If ExpiresIn is -1, the system considers it as a infinite life time. If it is not specified, the system applies a default value configured at system level.

Any integer, including -1 (which indicates that access tokens do not expire).

The expiration can also be set using a reference to a variable, as follows.

<ExpiresIn ref="flow.variable">{default_value}</ExpiresIn>

All
ReuseRefreshToken Indicates whether a new RefreshToken should be issued when a valid RefreshToken is presented. When set to true, the existing RefreshToken is reused until it expires.

true or false

All except client credentials and implicit
RefreshTokenExpiresIn Enforces the expiry time of refresh tokens in milliseconds. 

Any integer, including -1 (which indicates that refresh tokens do not expire)

The expiration can also be set using a reference to a variable, as follows.

<RefreshTokenExpiresIn ref="flow.variable">{default_value}</RefreshTokenExpiresIn>

All except client credentials and implicit
SupportedGrantTypes Specifies the GrantTypes supported by a token endpoint. An endpoint may support multiple GrantTypes (that is, a single endpoint can be configured to distribute access tokens for multiple GrantTypes.)
  • client_credentials
  • authorization_coe
  • password
  • implicit
All
Code The expected location in the request message where the authorization code must be presented to the token endpoint. Any variable setting. For example request.queryparam.auth_code indicates that the authorization code should be present as a query parameter, as, for example, ?auth_code=AfGlvs9. To require the authorization code in an HTTP header, for example, set this value to request.header.auth_code. GenerateAccessToken with grant type authorization_code
ClientId The expected location in the request message where the client_id (the app's consumer key) must be presented to the token endpoint. Any variable setting. For example request.queryparam.client_id indicates that the client_id should be present as a query parameter, as, for example, ?client_id=AfGlvs9. To require the ClientId in an HTTP header, for example, set this value to request.header.client_id. GenerateAccessTokenImplicit: Optional GenerateAuthorizationCode:Optional
RedirectUri The expected location in the request message where the RedirectUri must be presented to the token endpoint. Any variable setting. For example request.queryparam.redirect_uri indicates that the RedirectUri should be present as a query parameter, as, for example, ?redirect_uri=login.myapp.com. To require the RedirectUri in an HTTP header, for example, set this value to request.header.redirect_uri. GenerateAccessTokenImplicit: Optional GenerateAuthorizationCode:Optional
Scope The expected location in the request message where the scope must be presented to the token endpoint. Any variable setting. For example request.queryparam.scope indicates that the scope should be present as a query parameter, as, for example, ?scope=READ. To require the scope in an HTTP header, for example, set this value to request.header.scope. All: Optional
State The expected location in the request message where the state must be presented to the token endpoint. Any variable setting. For example request.queryparam.state indicates that the state should be present as a query parameter, as, for example, ?state=HjoiuKJH32. To require the state in an HTTP header, for example, set this value to request.header.state. authorization_code, password
AppEndUser The expected location in the request message where the state must be presented to the token endpoint. Any variable setting. For example request.queryparam.app_enduser indicates that the AppEndUser should be present as a query parameter, as, for example, ?app_enduser=ntesla@theramin.com. To require the AppEndUser in an HTTP header, for example, set this value to request.header.app_enduser. All: Optional
UserName The expected location in the request message where the UserName must be presented to the token endpoint. Any variable setting. For example request.queryparam.username indicates that the username should be present as a query parameter, as, for example, ?username=joe. To require the UserName in an HTTP header, for example, set this value to request.header.username. All: Optional
Password The expected location in the request message where the Password must be presented to the token endpoint. Any variable setting. For example request.queryparam.password indicates that the Password should be present as a query parameter, as, for example, ?password=changeit. To require the Password in an HTTP header, for example, set this value to request.header.password. All: Optional
GenerateResponse An element used in token endpoints, authorization endpoints, and refresh endpoints to indicate that a response should be generated for requests, and that no further processing should take place. (Indicates that the policy is an endpoint.) N/A All: Optional

Customizing access tokens

Custom attributes can be optionally included in access tokens.

<Attributes> 
  <Attribute name="attr_name1" ref="flow.variable" display="true|false">value1</Attribute>
  <Attribute name="attr_name2" ref="flow.variable" display="true|false">value2</Attribute>
</Attributes>

Where display is set to true, custom attributes are returned in the response , where they may be viewable by the app end user.

Where display is set to false, custom attributes are stored in the data store, but are not returned in the response message.

For example, to add the User-Agent associated with the request to an access token:

<OAuthV2 name="GenerateAccessToken">
  <Operation>GenerateAccessToken
  </Operation>
  <ExpiresIn>1000</ExpiresIn>
  <GenerateResponse />
  <SupportedGrantTypes>
    <GrantType>client_credentials</GrantType>
  </SupportedGrantTypes>
  <GrantType>request.queryparam.grant_type</GrantType>
  <Attributes> 
    <Attribute name="user-agent" ref="request.header.user-agent" display="false"></Attribute>
  </Attributes>
</OAuthV2>

Delegating token management

Remote token stores can be used against Apigee Edge. If a remote token store is used, the following element should be configured in the GenerateAccessToken policy. When this configuration is used, Apigee Edge will generate the access token and return it to the requesting app.

<StoreToken>false</StoreToken>

If token validation has been delegated to a remote token service, then the following element must be configured, identifying the location of the token in the request message. By specifying an ExternalAccessToken element, you indicate that Apigee Edge should not attempt to validate the token.

<ExternalAccessToken> request.header.external_access_token | request.formparam.external_access_token | request.queryparam.external_access_token </ExternalAccessToken>

Note that if you configure an external access token service, you must implement a ServiceCallout that enforces the token check.

Such a ServiceCallout is beyond the scope of this document, so contact Apigee Support for more information on implementing integrations with remote token services.

Note: Only bearer tokens are currently supported. MAC tokens are not supported. The access token must be passed in the authorization header. For example, a sample authorization header is:

"Authorization: Bearer {access_token}"

Policy-specific variables

OAuth policies populate a large set of default variables.

For a comprehensive list, see OAuth flow variables.

Invalidating tokens

In some cases, apps are required to explicitly revoke or invalidate tokens, for example, when a user logs out of an OAuth-enabled app.

The procedure for token revocation is defined by the IETF Token Revocation draft specification.

The specification states:

[T]oken revocation prevents abuse of abandoned tokens and facilitates a better end-user experience since invalidated authorization grants will no longer turn up in a list of authorization grants the authorization server might present to the end-user.

Apigee Edge provides an InvalidateToken operation that enables you to configure a dedicated token revocation endpoint. By publishing the URI of this endpoint, you enable app developers to invalidate tokens issued by Edge.

For example:

<OAuthV2 name="InvalidateToken">
  <Operation>InvalidateToken</Operation>
  <Tokens>
    <Token type="accesstoken" cascade="true">flow.variable</Token>
    <Token type="refreshtoken" cascade="true">flow.variable</Token>
  </Tokens>
</OAuthV2>

Configure the InvalidateToken operation using the following elements.

Field Name Description
Tokens

Identifies the Flow variable that defines the source of the token to be revoked. If developers are expected to submit access tokens as query parameters named access_token, for example, use request.queryparam.access_token.

  • type (Optional): The token type identified by the variable specified. Supported values are accesstoken and refreshtoken.
  • cascade (Optional): A boolean that determines whether the revocation action will propagate to associated tokens. Supported values are true and false. Defaults to true if not configured.

You can use the same technique to approve access tokens. The OAuthV2 policy type supports a ValidateToken operation. The settings are the same as the InvalidateToken operation. The difference is that, by specifying the ValidateToken operation, the status of the targeted access token or refresh token from 'revoked' to 'approved'.

<OAuthV2 name="ValidateToken">
  <Operation>ValidateToken</Operation>
  <Tokens>
    <Token type="accesstoken" cascade="true">flow.variable</Token>
    <Token type="refreshtoken" cascade="true">flow.variable</Token>
  </Tokens>
</OAuthV2>

Auditing app end user consent

You may be required to verify that an app end user authorized an app.

You can use the Audit API to do so.

See Audits.

Policy schema

Each policy type is defined by an XML schema (.xsd). For reference, policy schemas are available on GitHub.

Comments

In the section Customizing access tokens, it is missing where the

value1
value2

Should be added in the policy.

Thanks, we added a sample to show how this is done.

AppEndUser Description in table is incorrect
---
The expected location in the request message where the state must be presented to the token endpoint.
---

Add new comment

Provide your email address if you wish to be contacted offline about your comment.
We will not display your email address as part of your comment.

We'd love your feedback and perspective! Please be as specific as possible.
Type the characters you see in this picture. (verify using audio)

Type the characters you see in the picture above; if you can't read them, submit the form and a new image will be generated. Not case sensitive.