Secure services

Resources on a server, such as services, layers, webmaps, or items may be secured to permit access to authorized users only. API classes such as AGSPortal, AGSWebMap, AGSLayer, AGSTask, etc which are initialized with a URL to a server-side resources, also optionally accept a credential that can be used to access that resource if it is secured.

Access secure services using credentials

If you know the credentials (user name and password) needed to access a secure service, pass these credentials to the layer/task through an AGSCredential object.

//create the credential
AGSCredential* cred = [[AGSCredential alloc] initWithUser:@"<user>" password:@"<password>"];    

//pass the credential to layer or task
AGSDynamicMapServiceLayer* layer = [AGSDynamicMapServiceLayer dynamicMapServiceLayerWithURL:url credential:cred ];    
AGSQueryTask* task = [AGSQueryTask queryTaskWithURL:url credential:cred];
The API tries to discover the authentication type (token or HTTP) used by the service.

HTTP authentication

If the service is using HTTP authentication, the credentials (user name and password) propagate to the service via HTTP request headers.

Token authentication

If the service is using token-based authentication, the API attempts to discover the URL of the token service where tokens can be acquired. If you know this information in advance, provide it to the AGSCredential object so that the API does not make any unnecessary network requests to discover the same information.

AGSCredential* cred = [[AGSCredential alloc] 

The layer/task propogates your credentials to the token service and transparently acquires a token on your behalf. The token is then included in every request to the service. When the token expires, the layer/task automatically acquires a fresh token.

Access secure services using client certificates

As an alternative to employing user credentials (user name/password combination) or tokens, use digital certificates to access services that are secured using HTTP authentication and Public Key Infrastructure (PKI). In such a scenario, each user who is authorized to access the service is provided a digital certificate (also known as client certificate), which can be used to confirm their identity when connecting to the service.

A certificate contains information about a user's identity and is usually endorsed or signed by a trusted entity, commonly known as a certification authority (CA). The entity can be external such as Verisign, Thawte, and so on, or it can be internal to the organization. The certificate also contains additional information such as its validity period, a serial number, public/private key combination, and so on, stored according to the x.509 format. The certificate file usually has a *.p12 or *.pfx file extension and must be installed on the user's device.

Install the certificate

To install a certificate on an OS X computer so that your custom app or apps can use it, do the following:

  1. Make the certificate available on the computer.
  2. Progamatically import the certificate into the keychain access group of your app.

There are many approaches you can take, but two options are discussed below.


If the user has email configured on the computer, the user's certifcate can be emailed to them as an attachment. However, if the certificate uses the default *.p12 or *.pfx file extension, the OS X system attempts to import the certificate into the default keychain when a user tries to open the attachment. Only system apps, such as Mail and Safari, can acess the default keychain. Custom apps do not get access to the default keychain, and as a result, your app won't be able to access the certificate.

To work around this problem, rename the certificate file to use a custom file extension, for example, *.myapp. Your custom app must also declare that it can handle files with such extensions. Now when a user taps the certificate attached in the email, your app invokes, and the certificate is passed to the app delegate. The app delegate can then import the certificate into the app's keychain access group as shown below:

-(BOOL)application:(NSApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
  //Read the contents of the certificate file as bytes
 	NSData *PKCS12Data = [[NSData alloc] initWithContentsOfURL:url];

	 //Import the certificate 
  NSError *error = nil;
  SecIdentityRef idRef = [AGSCredential importCertificateData:PKCS12Data password:@"<cert_password>" overwrite:YES error:&error];

Digital certificates are usually protected by a password to prevent unauthorized use. This password is required to import the certificate. If you don't have the password, you may need to prompt the user for it.

Access the secure service

Once the certificate installs on the device, use the identity within it to access services that are secured using PKI. To do this, initialize the AGSCredential object using a reference to the identity in the certificate.

//Reference to the identity in a certificate
SecIdentityRef idRef = ...;

AGSCredential* cred = [[AGSCredential alloc] initWithIdentityRef:idRef];

You get the reference to the identity when you import the certificate into the keychain as shown in the code previously.

Alternatively, you can also get a list of identities for certificates already imported into the keychain. You can then display this list to the user and ask them to pick one to use. To get a list of identites that you can use with a service, know the protection space of the service. The code below shows how you can handle a scenario in which a layer fails to load because of authentication failure while accessing a PKI secured service.

- (void)layer:(AGSLayer *)layer didFailToLoadWithError:(NSError *)error {
if ([error isAuthenticationError]) {

		NSURLProtectionSpace* pSpace = (error.userInfo)[@"protectionSpace"];
  if (pSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate) {

				//list of identities that can be used with the service
    NSArray *identities = [AGSCredential identitiesForProtectionSpace:pSpace];

    //if you find more than one identity, display the list to the user, ask them to pick one
				SecIdentityRef selectedIdentity = ...;

				//try to reload layer with the selected one
	    AGSCredential *cred = [[AGSCredential alloc] initWithIdentityRef:selectedIdentity];
    [layer resubmitWithURL:layer.URL credential:cred];

As you can see, the SDK does most of the heavy lifting to shield you from the low-level system details. See Apple's documentation for information on dealing with certificates, keychains, and identities.

Encrypting data using SSL

To safeguard content exchanged over the network from eavesdroppers and man-in-the-middle attacks, use HTTPS when supported by the service. This ensures your data, credentials, or tokens are not compromised. HTTPS connections use Secure Sockets Layer (SSL) to encrypt information exchanged over the network and digital certificates to verify identities of the parties involved.

Use self-signed certificates

There may be times when you encounter servers using a self-signed certificate with SSL. As a security measure, HTTPS connections are not established with a server that uses self-signed certificates. Digital certificates are a means to prove the identity of an entity and should ideally be endorsed (signed) by a known trusted authority to be credible. Anyone can create a digital certificate and sign it to establish a misleading identity.

When the API fails to establish an HTTPS connection, it provides an NSError object that can be inspected to verify the failure was because the server was using a self-signed certificate.

If you chose to trust a server that is using a self-signed certificate, for instance, if that server is used for development purposes, add the host name of the server to the trustedHosts property on the NSURLConnection class.

The following code snippet verifies a layer failed to load because the server was using a self-signed certificate, and if so, adds the server to trustedHosts and reloads the layer:

- (void)mapView:(AGSMapView *)mapView failedLoadingLayerForLayerView:(UIView<AGSLayerView> *)layerView baseLayer:(BOOL)baseLayer withError:(NSError *)error {

  //if error was becasue server was using a self-signed certificate
  if ([error code]== NSURLErrorServerCertificateUntrusted) {

   //You may want to prompt the user and ask if it is okay to establish connection with the server

   //Assuming here that the layer was a tiled layer. 
   //You will need to change this code to typecast it to the correct type
   AGSTiledMapServiceLayer* tiledLayer = (AGSTiledMapServiceLayer*)layerView.agslayer;
   //Add the server to the trusted hosts list
   [[NSURLConnection trustedHosts] addObject:[tiledLayer.URL host]];
   //Reload the layer
   [tiledLayer resubmitWithURL:tiledLayer.URL credential:scredential];

Alternatively, if you know in advance the server you will connect to uses a self-signed certificate, add it to the trustedHosts list as soon as the application starts. The following code snippet does this in the application delegate:

- (void)applicationDidFinishLaunching:(NSApplication *)application {


 [[NSURLConnection trustedHosts] addObject:@"<my_server>"];