Authenticating users and application clients

To protect your App Services application data, one of the steps you'll take is to authenticate your app's users. By ensuring that they are who they say they are, you can help ensure that your application's data is available in secure ways. After you've created permission rules that define access to your application and have associated these rules with users, you'll want to add code that authenticates your user, as described in this topic.

Authentication levels

App Services supports four levels of authentication:

  • Application user: Grant's user access to an API Services application, based on the roles and permissions assigned to the user.
  • Application client: Grants full access to perform API requests against an API Services application.
  • Organization client: Grants full access to perform API requests against an API Services organization.
  • Admin user: Grants full access to perform API requests against any API Services organization that the user is an admin of.

Because the scope of access provided by the application client, organization client, and admin user authentication levels is so broad (and as a result, so powerful), it's a bad practice to use them from a mobile app or any client-side code. Instead, they're better suited to server-side implementations, such as web applications.

For a more detailed description of available authentication levels, see Authentication levels.

Application user authentication (user login)

Using the username and password values specified when the user entity was created, your app can connect to the App Services application endpoint to request an access token. It's also acceptable to use the user's email address in place of the username.

Using the SDKs

When a user is logged in using the Apigee iOS, JavaScript, node.JS and Android SDKs, the returned token is automatically stored in the ApigeeDataClient (iOS), DataClient (Android), or Apigee.Client (JavaScript/node.JS) class instance, and will be sent to the API with all subsequent method calls.

cURL

Request syntax

curl -X POST "https://<baas_host_name>/<orgName>/<appName>/token" -d '{"grant_type":"password", "username":<username>, "password":<password>}'

Example request

curl -X POST "https://<baas_host_name>/my-org/my-app/token" -d '{"grant_type":"password", "username":"john.doe", "password":"testpw"}'
                

Example response

The results include the access token needed to make subsequent API requests on behalf of the application user:

{
"access_token": "5wuGd-lcEeCUBwBQVsAACA:F8zeMOlcEeCUBwBQVsAACA:YXU6AAABMq0hdy4Lh0ewmmnOWOR-DaepCrpWx9oPmw",
"expires_in": 3600,
"user": {
        ...
}
}
                

iOS

SDK method

(ApigeeClientResponse *)logInUser: (NSString *)userName password:(NSString *)password

Example request

//create an instance of AppDelegate
//we recommend you call ApigeeClient from your AppDelegate.
//for more information see the iOS SDK install guide:
//http://apigee.com/docs/app-services/content/installing-apigee-sdk-ios
AppDelegate *appDelegate = (AppDelegate *)[ [UIApplication sharedApplication] delegate];

//call logInUser to initiate the API call
ApigeeClientResponse *response = [appDelegate.dataClient logInUser:username password:password];
@try {
    //success - a token is returned in the response
}
@catch (NSException * e) {
    //fail - most likely a bad username/password
}                       
                

Example response

{
    "access_token" = "YWMtsi9ERF_EeOUIOc3TUbToQAAAUKb_OPzZmpWk6J7hwUZyY3w6FEIRtw8psA";
    "expires_in" = 604800;
    user =     {
        activated = 1;
        created = 1384203732578;
        email = "user@yourapp.com";
        modified = 1384203732578;
        name = someuser;
        picture = "http://www.gravatar.com/avatar/2076105f6efe7c11e285add95f514b9a";
        type = user;
        username = someuser;
        uuid = "89469434-4b14-11e3-ae68-ff6ddb9bb1aa";
    };
}                       
                

Android

SDK method

authorizeAppUserAsync(final String email, final String password, final ApiResponseCallback callback)

Example request

//dataClient is your instance of the ApigeeClient class
dataClient.authorizeAppUserAsync(username, password, new ApiResponseCallback() {
        
        //If authorizeAppUserAsync fails, catch the error
        @Override
        public void onException(Exception e) { 
                // Error
        }
        
        //If successful, handle the response object
        @Override
        public void onResponse(ApiResponse response) {
            try { 
                if (response != null) {
                    // Success - access token is returned in the response
                }
            } catch (Exception e) {
                        // Fail - most likely a bad username/password
            }
    }
});                             
                

Example response

{
   "rawResponse":"{"   access_token":"KlJAEeOE68s4qMeT8wAAAUKcCAYzmdaUteMnqjQ3o46uuwKhoz08WyIYWMt5A84",
   "expires_in":604800,
   "user":{
      "uuid":"89469434-4b14-11e3-ae68-ff6ddb9bb1aa",
      "type":"user",
      "name":"someuser",
      "created":1384203732578,
      "modified":1384203732578,
      "username":"someuser",
      email = "user@yourapp.com",
      "activated":true,
      "picture":"http://www.gravatar.com/avatar/2076105f6efe7c11e285add95f514b9a"
   }
}","user":{
   "dataClient":null,
   "email":"user@yourapp.com",
   "name":"someuser",
   "picture":"http://www.gravatar.com/avatar/2076105f6efe7c11e285add95f514b9a",
   "username":"someuser",
   "activated":true,
   "disabled":false,
   "type":"user",
   "uuid":"89469434-4b14-11e3-ae68-ff6ddb9bb1aa",
   "created":1384203732578,
   "modified":1384203732578
},
"timestamp":0,
"entityCount":0,
"firstEntity":null,
"lastEntity":null,
"access_token":"KlJAEeOE68s4qMeT8wAAAUKcCAYzmdaUteMnqjQ3o46uuwKhoz08WyIYWMt5A84",
"expires_in":604800
}                       
                

JavaScript (HTML5)

The example assumes use of the JavaScript (HTML5) SDK.

SDK method

login(username, password, callback)

Example request

dataClient.login(username, password, function (error,response) {
        if (error) {
            //error — could not log user in
        } else {
            //success — user has been logged in
            var token = dataClient.token;
        }
    }
);
                

Example response

Object {access_token: "hFLaEeOVvSEuHOLs0wAAAUKf83n9O4Tll-djK8Ghq5GdHIQZ7xrpoOsYWMtAWpO", expires_in: 604800, user: Object}
        access_token: "hFLaEeOVvSEuHOLs0wAAAUKf83n9O4Tll-djK8Ghq5GdHIQZ7xrpoOsYWMtAWpO"
        expires_in: 604800
        user: Object
                activated: true
                created: 1384203732578
                email: "user@yourapp.com"
                modified: 1384203732578
                name: "someuser"
                picture: "http://www.gravatar.com/avatar/2076105f6efe7c11e285add95f514b9a"
                type: "user"
                username: "someuser"
                uuid: "89469434-4b14-11e3-ae68-ff6ddb9bb1aa"
                __proto__: Object
__proto__: Object
                

Ruby

The example assumes use of the Ruby SDK.

SDK method

login (username, password)

Example request

app = Usergrid::Application.new 'https://<baas_host_name>/my-org/my-app/'
app.login username, password
token = app.auth_token
                

Example response

                
{
   "access_token":"elLbEeOo8v2Z0bwpxQAAAUKf-xnbGtl3gehLTR9NWV26bPlQ0XMeW5oYWMtKz8N",
   "expires_in":604800,
   "user":{
      "uuid":"89469434-4b14-11e3-ae68-ff6ddb9bb1aa",
      "type":"user",
      "name":"someuser",
      "created":1384203732578,
      "modified":1384203732578,
      "username":"someuser",
      "email":"user@yourapp.com",
      "activated":true,
      "picture":"http://www.gravatar.com/avatar/2076105f6efe7c11e285add95f514b9a"
   }
}
                

Node.js

The example assumes use of the Node.js module.

SDK method

login(username, password, callback)

Example request

var username = 'testuser';
var password = 'testpasswd';
dataClient.login(username, password, function (error, response) {
        if (error) {
            //error — could not log user in
        } else {
            //success — user has been logged in
            var token = client.token;
        }
    }
);
                

Example response

{ access_token: 'iFLbEeOyfrF-3pXAxgAAAUKf_4xzyktaBBm8jmP4bnbd9avblkB14CMYWMt2Ptx',
  expires_in: 604800,
  user:
   { uuid: '89469434-4b14-11e3-ae68-ff6ddb9bb1aa',
     type: 'user',
     name: 'someuser',
     created: 1384203732578,
     modified: 1384203732578,
     username: 'someuser',
     email: 'user@yourapp.com',
     activated: true,
     picture: 'http://www.gravatar.com/avatar/2076105f6efe7c11e285add95f514b9a' } 
}                       
                

Application client authentication

Using your app’s client id and client secret values, your app can connect to the App Services application endpoint to request an access token. The client ID and secret for your app can be found in 'Getting Started' section of the API Services admin portal, under 'Server App Credentials'.

cURL

Request syntax

curl -X POST "https://<baas_host_name>/<orgName>/<appName>/token" -d '{"grant_type":"client_credentials", "client_id":<application_clientID>, "client_secret":"<application_client_secret>"}'

Example request

curl -X POST "https://<baas_host_name>/my-org/my-app/token" -d '{"grant_type":"client_credentials", "client_id":"YXB7NAD7EM0MEeJ989xIxPRxEkQ", "client_secret":"YXB7NAUtV9krhhMr8YCw0QbOZH2pxEf"}'
                

Example response

The results include the access token needed to make subsequent API requests on behalf of the application:

{
"access_token": "F8zeMOlcEeCUBwBQVsAACA:YXA6AAABMq0d4Mep_UgbZA0-sOJRe5yWlkq7JrDCkA",
"expires_in": 3600,
"application": {
...  
}
}
                

Ruby

SDK method

Application.login_credentials(client_id,client_secret)

Example request

#Create a client object                         
usergrid_api = 'https://<baas_host_name>'
organization = 'your-org'
application = 'your-app'
client_id = 'XDDE4kFHkO12EeKkN_UdQDp84g'
client_secret = 'DSE4frScUIfOZCU7_-CeRJgm-pvUaRo'

client = Usergrid::Application.new "#{usergrid_api}/#{organization}/#{application}"

begin
        # Call login_credentials to initiate the API call
        # and save the response
        response = client.login_credentials(client_id,client_secret)
rescue
        #fail
end                     
                

Example response

{
        "access_token":"SDde04kfKpj9EeOJCI8033US_AAAAURrmlkoUvIejKsEDE1FpIfZDHXIfcdrchg",
        "expires_in":604800,
        "application":"524sd90-ed76-11e2-a437-f51d403a7ce2"
}                       
                

Node.js

SDK method

request(options, callback)

Example request

//initialize the SDK            
var dataClient = new Usergrid.client({
        orgName:'your-org',
        appName:'your-app',
    });

//options for the request
var options = {
        endpoint:"token", //management token endpoint
        method:"POST",
        body: {
                //our client credentials and OAuth grant type
            client_id: 'b3U68vghI6FmDSCd34e4Gtzz0A',
            client_secret: 'b3U6QPkNDDSedF4sel3MCJ0haHKynew',
            grant_type: "client_credentials"
    }
}

dataClient.request(options, function (error, result) {

        if (error) { 
            // Error
        } else { 
                // Success
        }

});                     
                

Example response

{ access_token: 'YWMtXcSPBpkSDcfr95kF9-IhTgAAAURrtfFyUyP_0ESa3qQnarknlIIXY0BQrzA',
  expires_in: 604800,
  application: '5d554790-ed76-11e2-a437-f51dskd9er4e' }
                

Admin user authentication

If you do require admin user access, your app can connect to the App Services management endpoint to request an access token. Your app supplies the username and password of an admin user in the request.

cURL

Request syntax

curl -X POST "https://<baas_host_name>/management/token" -d '{"grant_type":"password", "username":<admin_username>, "password":<admin_password>}'

Example Request

curl -X POST "https://<baas_host_name>/management/token"  -d '{"grant_type":"password", "username":"testadmin", "password":"testadminpw"}'

Example response

The results include the access token needed to make subsequent API requests on behalf of the admin user:

{
        "access_token": "f_GUbelXEeCfRgBQVsAACA:YWQ6AAABMqz_xUyYeErOkKjnzN7YQXXlpgmL69fvaA",
        "expires_in": 3600,
        "user": {
                ...
        }
}                   
                

iOS

SDK method

(ApigeeClientResponse *)apiRequest: (NSString *)url operation:(NSString *)op data:(NSString *)opData

Example request

//create an instance of AppDelegate
//we recommend you call ApigeeClient from your AppDelegate.
//for more information see the iOS SDK install guide:
//http://apigee.com/docs/app-services/content/installing-apigee-sdk-ios
AppDelegate *appDelegate = (AppDelegate *)[ [UIApplication sharedApplication] delegate];

NSString *url = @"https://<baas_host_name>/management/token";
NSString *op = @"POST";

//Retrieve user credentials from input. Never hard code.
NSString *username;
NSString *password;

//construct the body of our request
NSString *options = [NSString stringWithFormat:@"%@%@%@%@%@", @"{\"username\":\"", username, @"\",\"password\":\"", password, @"\",\"grant_type\":\"password\"}"];

ApigeeClientResponse *response = [appDelegate.dataClient apiRequest:url operation:op data:options];

@try {
    NSLog(@"%@",response.response);
    
}
@catch (NSException * e) {
    NSLog(@"false");
    
}                       
                

Example response

{
    "access_token" = "YWMtx2aSdtrwEeOAsG_KkyBJVSDC45fsr5xNF5f9aUf-nk7saByvfij39vVb2pA";
    "expires_in" = 604800;
    passwordChanged = 1380058452528;
    user =     {
        activated = 1;
        adminUser = 1;
        applicationId = "00000000-0000-0000-0000-000000000001";
        confirmed = 1;
        disabled = 0;
        displayEmailAddress = "someUser <someUser@yourcompany.com>";
        email = "someUser@yourcompany.com";
        htmldisplayEmailAddress = "someUser <someUser@yourcompany.com>";
        name = someUser;
        organizations =         {
            someOrg =             {
                applications =                 {
                    "someOrg/someApp" = "b9f298c0-3797-11e3-badf-87e30cd375d2";
                    "someOrg/someOtherApp" = "5d554790-ed76-11e2-a437-f51d403a7ce2";
                };
                name = someOrg;
                properties =                 {
                };
                users =                 {
                    someUser =                     {
                        activated = 1;
                        adminUser = 1;
                        applicationId = "00000000-0000-0000-0000-000000000001";
                        confirmed = 1;
                        disabled = 0;
                        displayEmailAddress = "someUser <someuser@yourcompany.com>";
                        email = "someUser@yourcompany.com";
                        htmldisplayEmailAddress = "someUser <someUser@yourcompany.com>";
                        name = someUser;
                        properties =                         {
                            passwordPolicyId = 15;
                        };
                        username = someUser;
                        uuid = "s87fm423-a166-11e2-a7f7-02e81sid9fr3";
                    };
                };
                uuid = "s87fm423-a166-11e2-a7f7-02e81sid9fr3";
            };
        };
        properties =         {
            passwordPolicyId = 15;
        };
        username = someUser;
        uuid = "f25sdfr3w-a166-11e2-a7f7-02e81adcf3d0";
    };
}                       
                

Android

Admin user authentication is currently not supported by the Apigee Android SDK.

JavaScript

SDK method

request(options, callback)

Example request

//Initialize the SDK
var dataClient = new Apigee.Client({
    orgName:'your-org',
    appName:'your-app',
});

//Retrieve user credentials from input. Never hard code.
var username;
var password;
    
//options for the request
var options = {
        endpoint:'management/token', //management token endpoint
        method:'POST',
        mQuery: true, //specifies that we are not targeting an orgName/appName endpoint
        body: {
                //our user credentials and OAuth grant type
            username: username,
            password: password,
            grant_type: 'password'
    }
}

dataClient.request(options, function (error, result) {

        if (error) { 
            // Error
        } else { 
                // Success
        }

});
                

Example response

Object {passwordChanged: 1380058452528, access_token: "YWDfetkz8pjTEeOU8KtgtjfgWwAAAURqhwtqePwhRrB61u2CB665tRGBJ184Iek", expires_in: 604800, user: Object}
access_token: "YWDfetkz8pjTEeOU8KtgtjfgWwAAAURqhwtqePwhRrB61u2CB665tRGBJ184Iek"
expires_in: 604800
passwordChanged: 1380058452528
user: Object
        activated: true
        adminUser: true
        applicationId: "00000000-0000-0000-0000-000000000001"
        confirmed: true
        disabled: false
        displayEmailAddress: "someUser <someuser@yourcompany.com<"
        email: "someUser@yourcompany.com"
        htmldisplayEmailAddress: "someUser <someUser@yourcompany.com>"
        name: "someUser"
organizations: Object
        someOrg: Object
        someOtherOrg: Object
__proto__: Object
properties: Object
        username: "someUser"
        uuid: "f2935781-a166-11e2-a7f7-02e81adcf3d0"
__proto__: Object
__proto__: Object                       
                

Ruby

The example assumes use of the Ruby SDK.

SDK method

//Targets the /management endpoint
Usergrid::Management.new <base_url>
//Performs the admin user login
login <username>, <password>
                

Example Request

mgmt = Usergrid::Management.new 'https://<baas_host_name>/'
mgmt.login username, password
token = mgmt.auth_token
                

Example response

{
  "action" : "get admin user",
  "status" : "ok",
  "data" : {
    "organizations" : {
      "someOrg" : {
        "users" : {
          "someUser" : {
            "applicationId" : "00000000-0000-0000-0000-000000000001",
            "username" : "someUser",
            "name" : "someUser",
            "email" : "someUser@yourcompany.com",
            "activated" : true,
            "confirmed" : true,
            "disabled" : false,
            "properties" : {
              "passwordPolicyId" : 15
            },
            "uuid" : "sk9d8vfr-a166-11e2-a7f7-02e81adcf3d0",
            "adminUser" : true,
            "displayEmailAddress" : "someUser <someUser@yourcompany.com>",
            "htmldisplayEmailAddress" : "someUser <<a href=\"mailto:someUser@yourcompany.com\">someUser@yourcompany.com</a>>"
          },
        },
        "name" : "someUser",
        "applications" : {
          "someUser/someApp" : "5d554790-ed76-11e2-a437-sk9d8vfr7ce2",
        },
        "properties" : { },
        "uuid" : "sk9d8vfr-a166-11e2-a7f7-02e81adcf3d0"
      }
    },
    "applicationId" : "00000000-0000-0000-0000-000000000001",
    "properties" : {
      "passwordPolicyId" : 15
    },
    "htmldisplayEmailAddress" : "someUser <someUser@yourcompany.com>",
    "username" : "someUser",
    "confirmed" : true,
    "token" : "YWMtfrW-xSD9fkErfe_DIYAtTAAASDCci9rfxbicVvX4S5W5jie5wc55D9seD5k",
    "email" : "someUser@yourcompany.com",
    "adminUser" : true,
    "name" : "someUser",
    "activated" : true,
    "uuid" : "sk9d8vfr-a166-11e2-a7f7-02e81adcf3d0",
    "displayEmailAddress" : "someUser <someuser@yourcompany.com>",
    "disabled" : false
  },
  "timestamp" : 1392763155175,
  "duration" : 110
}

                

Node.js

The example assumes use of the Node.js module.

SDK method

request(options, callback)

Example request

//initialize the SDK
var dataClient = new Usergrid.client({
    orgName:'your-org',
    appName:'you-app',
});

//Retrieve user credentials from input. Never hard code.
var username;
var password;

//options for the request
var options = {
        endpoint:"management/token", //management token endpoint
        method:"POST",
        mQuery: true, //specifies that we are not targeting an orgName/appName endpoint
        body: {
                //our user credentials and OAuth grant type
            username: username,
            password: password,
            grant_type: "password"
    }
}

//the actual API call
dataClient.request(options, function (error, result) {

        if (error) { 
            // Error
        } else { 
        console.log(result);
                // Success
        }

});             

Example response

Note that the organizations the user has access to are returned in the organizations property.

{ passwordChanged: 1380058452528,
  access_token: 'YSDFrlPA8pjWEeOEvE96qf4eJgAAAURqmyDw2y5JcsEtsIUEt8V0xYsmVkP-MlY',
  expires_in: 604800,
  user: 
   { organizations: { someOrg: [Object], someOtherOrg: [Object] },
     applicationId: '00000000-0000-0000-0000-000000000001',
     properties: { passwordPolicyId: 15 },
     htmldisplayEmailAddress: 'someUser <<a href="mailto:user@yourcompany.com">user@yourcompany.com</a>>',
     username: 'someUser',
     confirmed: true,
     email: 'user@yourcompany.com',
     adminUser: true,
     name: 'someUser',
     activated: true,
     uuid: 'f2936541-a166-11e2-a7f7-02e81adcf3d0',
     displayEmailAddress: 'someUser <user@yourcompany.com>',
     disabled: false } }                        
                

Organization client authentication

If you do require organization level access, your app can connect to the App Services management endpoint to request an access token. Access to an organization requires the client id and client secret credentials. The client ID and secret for your organization can be found on the 'Org Administration' page of the API Services admin console under 'Organization API Credentials'.

cURL

Request syntax

curl -X POST "https://<baas_host_name>/management/token" -d '{"grant_type":"client_credentials", "client_id":<org_clientID>, "client_secret":<org_client_secret>}'

Example request

curl -X POST "https://<baas_host_name>/management/token" -d '{"grant_type":"client_credentials", "client_id":"YXB7NAD7EM0MEeJ989xIxPRxEkQ", "client_secret":"YXB7NAUtV9krhhMr8YCw0QbOZH2pxEf"}'
        

Example response

The results include the access token needed to make subsequent API requests to the organization:

{
        "access_token": "gAuFEOlXEeCfRgBQVsAACA:b3U6AAABMqz-Cn0wtDxxkxmQLgZvTMubcP20FulCZQ",
        "expires_in": 3600,
        "organization": {
                ...
        }
}
            
                

Ruby

SDK method

Organization.login_credentials(client_id, client_secret)

Example request

#Create a client object
usergrid_api = 'https://<baas_host_name>/management'
client_id = 'ks8dfFgrI6FmEeKn9wLoGtzz0A'
client_secret = 'so309dfFkJj0O5tCel3MCJ0haHKynew'

client = Usergrid::Organization.new "#{usergrid_api}"

begin
        # Call login_credentials to initiate the API call
        response = client.login_credentials(client_id,client_secret)
rescue
        #fail
end             
                

Example response

{
  "access_token": "YWMt-SDE9df-EeOyde1l_ts0AwAAAURrpjskIfMxjsdZ04S_2_nK5PLPUJyske4",
  "expires_in": 604800,
  "organization": {
    "users": {
      "someUser": {
        "applicationId": "00000000-0000-0000-0000-000000000001",
        "username": "someUser",
        "name": "someUser",
        "email": "someUser@yourcompany.com",
        "activated": true,
        "confirmed": true,
        "disabled": false,
        "properties": {
          "passwordPolicyId": 15
        },
        "uuid": "f2903878-a166-11e2-a7f7-02e81xod04rf",
        "adminUser": true,
        "displayEmailAddress": "someUser <someUser@yourcompany.com>",
        "htmldisplayEmailAddress": "someUser <<a href=\"mailto:someUser@yourcompany.com\">someUser@yourcompany.com<\/a>>"
      }
    },
    "name": "someOrg",
    "applications": {
      "someUser\/someApp": "s994kdf0-ed76-11e2-a437-f51d403a7ce2",
      "someUser\/someOtherApp": "slde3320-d7a8-11e2-9ce3-f315e5aa568a",
    },
    "uuid": "ddle04r3-a166-11e2-a7f7-02e81adcf3d0",
    "properties": {
      
    },
    "passwordHistorySize": 0
  }
}                       
                

Node.js

SDK method

request(options, callback)

Example request

//initialize the SDK            
var dataClient = new Usergrid.client({
        orgName:'your-org',
        appName:'your-app',
    });

//options for the request
var options = {
        endpoint:"management/token", //management token endpoint
        method:"POST",
        mQuery: true, //specifies that we are not targeting an orgName/appName endpoint
        body: {
                //our client credentials and OAuth grant type
            client_id: 'b3U68vghI6FmDSCd34e4Gtzz0A',
            client_secret: 'b3U6QPkNDDSedF4sel3MCJ0haHKynew',
            grant_type: "client_credentials"
    }
}

dataClient.request(options, function (error, result) {

        if (error) { 
            // Error
        } else { 
                // Success
        }

});                     
                

Example response

{ access_token: 'YWMtWVds34RDeXOMqbeSTFNLYQAAAURrr0bJMH1fvTGTT1Ddrclr_T3L4jLI6-8',
  expires_in: 604800,
  organization: 
   { users: 
      { someUser: [Object] },
     name: 'someOrg',
     applications: 
      { 'someOrg/someApp': 'sk8dfvew-ed76-11e2-a437-f51d403a7ce2',
        'someOrg/someOtherApp': 'sld90fre-d7a8-11e2-9ce3-f315e5aa568a',
     uuid: 's00ddf4w-a166-11e2-a7f7-02e81adcf3d0',
     properties: {},
     passwordHistorySize: 0 } }                 
                
Was this page helpful? Let us know how we did:

Send feedback about...

Apigee Docs