OAuth 2.0 defines a protocol for securing application access to protected resources, which are accessed through APIs. OAuth 2.0 relies on access tokens presented via apps on behalf of app end users when requesting RESTful resources via APIs. These tokens must be obtained before the app can access the protected resource. An access token contains a set of attributes and policies that relate to both the app and the app end user, and these attributes are used for making authorization decisions at run time.
Sample Code For working examples of OAuth 2.0-enabled API proxies, please refer to the API Platform samples available on GitHub.
Developer Guide For instructions on configuring OAuth 2 on the API Platform, refer to Configuring OAuth in the API Platform Developer Guide.
Setting up OAuth 2.0 is a three step process:
- Configure a token endpoint: An OAuth token endpoint defines a URI on the API Platform. The token endpoint is configured with a policy of type
OAUthV2. In theOAUthV2policy, 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 the API Platform manage OAuth-based authorization. - Apply an OAuth validation policy to protected resource URIs: To enforce OAuth at runtime, attach a policy of type
OAUthV2to a Flow that exposes a protected resource. In theOAUthV2policy, specify theVerifyAccessTokenoperation. - Configure one or more API products: The
VerifyAccessTokenoperation 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.
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. It is recommended that you deploy a single API proxy to function as a token endpoint for all API proxies in an environment.
A token endpoint is simply a URI path that the system uses to identify requests for access tokens. Strictly speaking, a token endpoint is a conditional flow to which an OAuthV2 policy specified 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.
Developer Guide 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. The API Platform 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 implemented for browser-based apps implemented in scripting languages such as JavaScript |
Resource Owner Password Credentials |
Used only when apps are trusted, enables a user to obtain an access token in return for provide 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. |
Validating 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 verified, 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:
<ProxyEndpoint name="default">
<PreFlow>
<Request>
<Step><Name>VerifyOAuthAccessToken</Name></Step>
</Request>
</PreFlow>
<!-- Remainder of ProxyEndpoint configuration -->
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 /> </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 /> </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: 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. |
|||
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 |
|
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) | All |
SupportedGrantTypes |
Specifies the GrantTypes supported by a token endpoint. An endpoint may support multiple GrantTypes (that is, a single endpoint can be configured distribute access tokens for multiple GrantTypes.) | GenerateAccessToken | 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 name of the policy. Must be unique within the API proxy configuration | 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. |
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.app_enduser indicates that the AppEndUser should be present as a query parameter, as, for example, ?app_enduser=ntesla@theramin.com. 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 message, 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.
Delegating token management
Remote token stores can be used against the API Platform. If a remote token store is used, the following element should be configured in the GenerateAccessToken policy.
<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 the API Platform 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 support for 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 support@apigee.com 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 {Base64_Of_AccessToken}".
For information on flow variables populated during the policy execution, refer to OAuth flow variables.
Policy schema
Each policy must conform to a policy schema. All policy constructs such as elements and attributes mentioned above are defined in a schema. To download the schema, click here.