Search code examples
swiftamazon-web-servicesamazon-cognitoaws-appsync

Appsync return 401 errors when connecting with cognito


So I've set up cognito and appsync and connected them both to my iOS client. Appsync works great from the console, but when i make any requests from iOS i get a 401 error without any error messages. I'm able to sign in and out of cognito fine. I think i might be passing the wrong thing in to something maybe?

Here's my app delegate code: import UIKit import AWSAppSync import AWSS3 import AWSCognitoIdentityProvider

var credentialsProvider: AWSCognitoCredentialsProvider?
var pool: AWSCognitoIdentityUserPool?

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var storyboard: UIStoryboard? {
        return UIStoryboard(name: "Main", bundle: nil)
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        AWSDDLog.sharedInstance.logLevel = .verbose
        AWSDDLog.add(AWSDDTTYLogger.sharedInstance)
        let configuration = AWSServiceConfiguration(region: AWSRegion, credentialsProvider: nil)

        let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: CognitoAppId, clientSecret: nil, poolId: CognitoPoolId)

        AWSCognitoIdentityUserPool.register(with: configuration, userPoolConfiguration: poolConfiguration, forKey: CognitoIdentityPoolId)

        pool = AWSCognitoIdentityUserPool(forKey: CognitoIdentityPoolId)

        NSLog("cognito pool username: \(pool?.currentUser()?.username ?? "unknown")")
        pool!.delegate = self

        credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegion, identityPoolId: CognitoIdentityPoolId, identityProviderManager: pool!)

        let databaseURL = URL(fileURLWithPath:NSTemporaryDirectory()).appendingPathComponent(database_name)

        do {
            // Initialize the AWS AppSync configuration
            let appSyncConfig = try AWSAppSyncClientConfiguration(url: AppSyncEndpointURL, serviceRegion: AWSRegion,
                                                                  credentialsProvider: credentialsProvider!,
                                                                  databaseURL:databaseURL)

            // Initialize the AppSync client
            appSyncClient = try AWSAppSyncClient(appSyncConfig: appSyncConfig)

            // Set id as the cache key for objects
            appSyncClient?.apolloClient?.cacheKeyForObject = { $0["id"] }
        }
        catch {
            NSLog("Error initializing appsync client. \(error)")
        }

        return true
    }

}

extension AppDelegate: AWSCognitoIdentityInteractiveAuthenticationDelegate {

    func startPasswordAuthentication() -> AWSCognitoIdentityPasswordAuthentication {
        let tabController = self.window?.rootViewController as! UITabBarController


        let loginViewController = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController


        DispatchQueue.main.async {
            tabController.present(loginViewController, animated: true, completion: nil)
        }

        return loginViewController
    }
}

and heres the error i'm getting:

Error body: {
  "errors" : [ {
    "message" : "Unable to parse JWT token."
  } ]
})
errorDescription: (401 unauthorized) Did not receive a successful HTTP code.

iam policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "appsync:GraphQL",
            "Resource": "*"
        }
    ]
}

IAM TRust relationship:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "cognito-identity.amazonaws.com:aud": "us-west-2:94OBSCURED"
        }
      }
    }
  ]
}

Let me know if you need more detail.


Solution

  • Ok the issue was: If you're using the code above, you need to set your appsync to authenticate via IAM (not Cognito). This will also require changes to your resolvers since the parameters passed to the identity object are different for IAM vs Cognito.

    This is confusing because you're using Cognito (both a user pool and a federated identity user pool), but do NOT chose Cognito.