Describe the bug
I am not able to call the admin query created by the amplify CLI via the Amplify API call. I always get unauthorized.
â–¿ APIError: The HTTP response status code is [401].
Recovery suggestion: The metadata associated with the response is contained in the HTTPURLResponse.
For more information on HTTP status codes, take a look at
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
â–¿ httpStatusError : 2 elements
- .0 : 401
- .1 : <NSHTTPURLResponse: 0x600002ee7b20> { URL: https://oall6h52m6.execute-api.us-west-2.amazonaws.com/dev/createUser } { Status Code: 401, Headers {
"Content-Length" = (
26
);
"Content-Type" = (
"application/json"
);
Date = (
"Sat, 13 Mar 2021 23:06:18 GMT"
);
Via = (
"1.1 c20831c51415172b5e09631b0a5bbb1f.cloudfront.net (CloudFront)"
);
"x-amz-apigw-id" = (
"cJfIpFUjvHcFwVw="
);
"x-amz-cf-id" = (
"y6fi6A8V1ZyGN0RDLX2mMiO2pAVfPOb-ql4NR_5HNFVosiJJWDkljA=="
);
"x-amz-cf-pop" = (
"LAX50-C1"
);
"x-amzn-errortype" = (
UnauthorizedException
);
"x-amzn-requestid" = (
"835aaa27-0102-4e84-b274-e701a4d322c1"
);
"x-cache" = (
"Error from cloudfront"
);
} }
This is my code:
let apiName = "AdminQueries"
let path = "/createUser"
let headers = ["Access-Control-Allow-Origin": "*"]
struct CognitoUser: Codable {
let name: String
let username: String
}
let cognitoUser = CognitoUser(name:name, username: email)
let encoder = JSONEncoder()
do {
let data = try encoder.encode(cognitoUser)
let request = RESTRequest(apiName: apiName, path: path, headers: headers, queryParameters: nil, body: data)
print(request)
createUserCancellable = Amplify.API.post(request: request)
.resultPublisher
.receive(on: DispatchQueue.main)
.sink { (completion) in
switch completion {
case .failure(let err):
self.errorMessage = err.localizedDescription.description
case .finished:
print("call to admin query api complete")
}
} receiveValue: { (data) in
self.successMessage = "The User was successfully created and will receive an email to complete sign up. Once they complete sign up, they will show up in your Clients list."
self.hasSuccessMessage = true
}
} catch let err {
errorMessage = err.localizedDescription.description
}
If I print the request you are making it looks like:
â–¿ https://oall6h52m6.execute-api.us-west-2.amazonaws.com/dev/createUser
â–¿ url : Optional<URL>
â–¿ some : https://oall6h52m6.execute-api.us-west-2.amazonaws.com/dev/createUser
- _url : https://oall6h52m6.execute-api.us-west-2.amazonaws.com/dev/createUser
- cachePolicy : 0
- timeoutInterval : 60.0
- mainDocumentURL : nil
- networkServiceType : __C.NSURLRequestNetworkServiceType
- allowsCellularAccess : true
â–¿ httpMethod : Optional<String>
- some : "POST"
â–¿ allHTTPHeaderFields : Optional<Dictionary<String, String>>
â–¿ some : 5 elements
â–¿ 0 : 2 elements
- key : "Access-Control-Allow-Origin"
- value : "*"
â–¿ 1 : 2 elements
- key : "X-Amz-Date"
- value : "20210313T231820Z"
â–¿ 2 : 2 elements
- key : "Content-Type"
- value : "application/json"
â–¿ 3 : 2 elements
- key : "Authorization"
- value : "XXX"
â–¿ 4 : 2 elements
- key : "User-Agent"
- value : "amplify-iOS/1.5.3 iOS/14.4 en_US"
â–¿ httpBody : Optional<Data>
â–¿ some : 55 bytes
- count : 55
â–¿ pointer : 0x00007ff87c11a000
- pointerValue : 140705210146816
â–¿ bytes : 55 elements
- 0 : 123
- 1 : 34
- 2 : 110
- 3 : 97
- 4 : 109
- 5 : 101
- 6 : 34
- 7 : 58
- 8 : 34
- 9 : 78
- 10 : 105
- 11 : 99
- 12 : 107
- 13 : 105
- 14 : 32
- 15 : 84
- 16 : 101
- 17 : 115
- 18 : 116
- 19 : 34
- 20 : 44
- 21 : 34
- 22 : 117
- 23 : 115
- 24 : 101
- 25 : 114
- 26 : 110
- 27 : 97
- 28 : 109
- 29 : 101
- 30 : 34
- 31 : 58
- 32 : 34
- 33 : 78
- 34 : 105
- 35 : 99
- 36 : 111
- 37 : 108
- 38 : 101
- 39 : 107
- 40 : 108
- 41 : 101
- 42 : 105
- 43 : 110
- 44 : 43
- 45 : 57
- 46 : 64
- 47 : 109
- 48 : 101
- 49 : 46
- 50 : 99
- 51 : 111
- 52 : 109
- 53 : 34
- 54 : 125
- httpBodyStream : nil
- httpShouldHandleCookies : true
- httpShouldUsePipelining : false
If I try to make my own request via url session like so, it works:
AppDelegate.getAccessToken { (token) in
guard let token = token else {
return
}
let semaphore = DispatchSemaphore (value: 0)
let parameters = "{\"name\":\"Nicki Test\",\"username\":\"[email protected]\"}"
let postData = parameters.data(using: .utf8)
var request = URLRequest(url: URL(string: "https://oall6h52m6.execute-api.us-west-2.amazonaws.com/dev/createUser")!,timeoutInterval: Double.infinity)
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("*", forHTTPHeaderField: "Access-Control-Allow-Origin")
request.addValue(token, forHTTPHeaderField: "Authorization")
request.addValue("20210313T215758Z", forHTTPHeaderField: "X-Amz-Date")
request.addValue("amplify-iOS/1.5.3 iOS/14.4 en_US", forHTTPHeaderField: "User-Agent")
request.httpMethod = "POST"
request.httpBody = postData
print(request)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data else {
print(String(describing: error))
return
}
print(String(data: data, encoding: .utf8)!)
semaphore.signal()
}
task.resume()
semaphore.wait()
}
Printing the request here before it's made it looks like:
â–¿ https://oall6h52m6.execute-api.us-west-2.amazonaws.com/dev/createUser
â–¿ url : Optional<URL>
â–¿ some : https://oall6h52m6.execute-api.us-west-2.amazonaws.com/dev/createUser
- _url : https://oall6h52m6.execute-api.us-west-2.amazonaws.com/dev/createUser
- cachePolicy : 0
- timeoutInterval : 60.0
- mainDocumentURL : nil
- networkServiceType : __C.NSURLRequestNetworkServiceType
- allowsCellularAccess : true
â–¿ httpMethod : Optional<String>
- some : "POST"
â–¿ allHTTPHeaderFields : Optional<Dictionary<String, String>>
â–¿ some : 5 elements
â–¿ 0 : 2 elements
- key : "Content-Type"
- value : "application/json"
â–¿ 1 : 2 elements
- key : "Access-Control-Allow-Origin"
- value : "*"
â–¿ 2 : 2 elements
- key : "User-Agent"
- value : "amplify-iOS/1.5.3 iOS/14.4 en_US"
â–¿ 3 : 2 elements
- key : "Authorization"
- value : "XXX"
â–¿ 4 : 2 elements
- key : "X-Amz-Date"
- value : "20210313T225642Z"
â–¿ httpBody : Optional<Data>
â–¿ some : 55 bytes
- count : 55
â–¿ pointer : 0x00007f83d78b9000
- pointerValue : 140204233691136
â–¿ bytes : 55 elements
- 0 : 123
- 1 : 34
- 2 : 110
- 3 : 97
- 4 : 109
- 5 : 101
- 6 : 34
- 7 : 58
- 8 : 34
- 9 : 78
- 10 : 105
- 11 : 99
- 12 : 107
- 13 : 105
- 14 : 32
- 15 : 84
- 16 : 101
- 17 : 115
- 18 : 116
- 19 : 34
- 20 : 44
- 21 : 34
- 22 : 117
- 23 : 115
- 24 : 101
- 25 : 114
- 26 : 110
- 27 : 97
- 28 : 109
- 29 : 101
- 30 : 34
- 31 : 58
- 32 : 34
- 33 : 78
- 34 : 105
- 35 : 99
- 36 : 111
- 37 : 108
- 38 : 101
- 39 : 107
- 40 : 108
- 41 : 101
- 42 : 105
- 43 : 110
- 44 : 43
- 45 : 54
- 46 : 64
- 47 : 109
- 48 : 101
- 49 : 46
- 50 : 99
- 51 : 111
- 52 : 109
- 53 : 34
- 54 : 125
- httpBodyStream : nil
- httpShouldHandleCookies : true
- httpShouldUsePipelining : false
The token values are removed here for security but they are the exact same. The only difference I notice between the requests are the headers are in a different order, the timeout time is 60 vs inifinite, neither of which should affect the request and give me an unauthorized request. Not sure if there is some other interception happening that I am missing in the code? It could be that I am also using Datastore and the categories don't know how to disambiguate between the apis in config- I saw this in the logs after updating my schema:
2021-03-13 21:26:51.123013-0800 VeesHoneyFoodDiary[4282:6052185] [RemoteSyncEngine] resolveReachabilityPublisher(): Unable to listen on reachability: APIError: Unable to determine which endpoint configuration
Recovery suggestion: Pass in the apiName to disambiguate between which endpoint
you are requesting reachability for
To Reproduce
Steps to reproduce the behavior:
Amplify.APIExpected behavior
Request succeeds
Environment(please complete the following information):
target 'VeesHoneyFoodDiary' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for VeesHoneyFoodDiary
pod 'Amplify'
pod 'AmplifyPlugins/AWSAPIPlugin'
pod 'AmplifyPlugins/AWSDataStorePlugin'
pod 'AmplifyPlugins/AWSCognitoAuthPlugin'
end
```
@kneekey23 Could you also post your amplifyconfiguration.json, appropriately redacted?
{
"UserAgent": "aws-amplify-cli/2.0",
"Version": "1.0",
"api": {
"plugins": {
"awsAPIPlugin": {
"amplifyDatasource": {
"endpointType": "GraphQL",
"endpoint": "https://XXXXXXXXX.appsync-api.us-west-2.amazonaws.com/graphql",
"region": "us-west-2",
"authorizationType": "AMAZON_COGNITO_USER_POOLS"
},
"AdminQueries": {
"endpointType": "REST",
"endpoint": "https://XXXXXXXexecute-api.us-west-2.amazonaws.com/dev",
"region": "us-west-2",
"authorizationType": "AMAZON_COGNITO_USER_POOLS"
}
}
}
},
"auth": {
"plugins": {
"awsCognitoAuthPlugin": {
"UserAgent": "aws-amplify/cli",
"Version": "0.1.0",
"IdentityManager": {
"Default": {}
},
"AppSync": {
"Default": {
"ApiUrl": "https://XXXXXXXXX.appsync-api.us-west-2.amazonaws.com/graphql",
"Region": "us-west-2",
"AuthMode": "AMAZON_COGNITO_USER_POOLS",
"ClientDatabasePrefix": "amplifyDatasource_AMAZON_COGNITO_USER_POOLS"
}
},
"CredentialsProvider": {
"CognitoIdentity": {
"Default": {
"PoolId": "us-west-2:XXXX",
"Region": "us-west-2"
}
}
},
"CognitoUserPool": {
"Default": {
"PoolId": "us-west-2_XXXXXXX",
"AppClientId": "XXXXXXX",
"AppClientSecret": "XXXXXX",
"Region": "us-west-2"
}
},
"Auth": {
"Default": {
"authenticationFlowType": "USER_SRP_AUTH"
}
}
}
}
}
}
@kneekey23 When you setup Admin Queries through the CLI, you provide with a Cognito userpool group that you'd like to have access to this API. Did you end up creating the Cognito userpool group manually or via the CLI and then add the user to that group?
@kaustavghosh06 I created the userpool group through the cli and it was much before I created this admin queries api. I did add the user to the Admins Group which i specified in the cli prompt as the name of the group id like to have access. It seems to work just fine if I hit the url myself logged in as the admin user as you can see from my manual request above not using the Amplify lib.
Hi @kneekey23, I attempted to reproduce it in this sample app and was able to call /getUser using an authenticated cognito user added to the "Admin" group (which I specified in the CLI as well).
Could you confirm which version of the plugins you are using in the Podfile.lock? Unlikely, but just to point out, the cognito user pool interceptor used to use the idToken and was updated to use the accessToken. This was released back in 1.1.0
By default, I do not have the /createUser API enabled in the lambda but I was able to get it working against GET /getUser. Could you try the request again but take a look at the response body? In 1.7.0 we released a way to retrieve the response body from the response:
import AmplifyPlugins
// Amplify.API failure case:
case .failure(let err):
print(err)
if case let .httpStatusError(statusCode, response) = err,
let awsResponse = response as? AWSHTTPURLResponse,
let responseBody = awsResponse.body
{
let str = String(decoding: responseBody, as: UTF8.self)
print(str)
}
What steps did you take to enable the /createUser and do other admin APIs work or not work with Amplify.API? getUser from sample app
why do you need let headers = ["Access-Control-Allow-Origin": "*"] in the headers? my Amplify.API request was working without it
This appears to be a issue with reachability in the sync engine and shouldn't impact most of the functionality of DataStore.
[RemoteSyncEngine] resolveReachabilityPublisher(): Unable to listen on reachability: APIError: Unable to determine which endpoint configuration
Recovery suggestion: Pass in the apiName to disambiguate between which endpoint
you are requesting reachability for
There is some logic in the API that is the reason for why DataStore's sync to cloud is working as expected in your app. API plugin atttempts to resolve the API from the configuration according to a best effort algorithm. API GraphQL requests (Amplify.API.mutate/query/subscribe) will use the only API configured when there's one, or if there's more than one it will use the only GraphQL API configured when there's two APIs of different types (your scenario), otherwise it will not know which API to call and require apiName to be passed in. (code)
It looks like the issue in the APIPlugins' Reachability API could be solved by extending it take in an endpoint type (REST or GraphQL) so that it can resolve to the single GraphQL endpoint when there is more than one API configured
hi @lawmicha, thanks for the detailed response. Still not sure how you got it working, as I am still experiencing the same error. How did you configure your categories? Did you test with both datastore set up and API?
PODS:
- Amplify (1.7.0):
- Amplify/Default (= 1.7.0)
- Amplify/Default (1.7.0)
- AmplifyPlugins/AWSAPIPlugin (1.7.0):
- AppSyncRealTimeClient (~> 1.4.0)
- AWSCore (~> 2.23.0)
- AWSPluginsCore (= 1.7.0)
- AmplifyPlugins/AWSCognitoAuthPlugin (1.7.0):
- AWSAuthCore (~> 2.23.0)
- AWSCognitoIdentityProvider (~> 2.23.0)
- AWSCognitoIdentityProviderASF (~> 2.23.0)
- AWSCore (~> 2.23.0)
- AWSMobileClient (~> 2.23.0)
- AWSPluginsCore (= 1.7.0)
- AmplifyPlugins/AWSDataStorePlugin (1.7.0):
- AWSCore (~> 2.23.0)
- AWSPluginsCore (= 1.7.0)
- SQLite.swift (~> 0.12.0)
- AppSyncRealTimeClient (1.4.3):
- Starscream (~> 3.1.0)
- AWSAuthCore (2.23.2):
- AWSCore (= 2.23.2)
- AWSCognitoIdentityProvider (2.23.2):
- AWSCognitoIdentityProviderASF (= 2.23.2)
- AWSCore (= 2.23.2)
- AWSCognitoIdentityProviderASF (2.23.2)
- AWSCore (2.23.2)
- AWSMobileClient (2.23.2):
- AWSAuthCore (= 2.23.2)
- AWSCognitoIdentityProvider (= 2.23.2)
- AWSCognitoIdentityProviderASF (= 2.23.2)
- AWSCore (= 2.23.2)
- AWSPluginsCore (1.7.0):
- Amplify (= 1.7.0)
- AWSCore (~> 2.23.0)
- SQLite.swift (0.12.2):
- SQLite.swift/standard (= 0.12.2)
- SQLite.swift/standard (0.12.2)
- Starscream (3.1.1)
DEPENDENCIES:
- Amplify
- AmplifyPlugins/AWSAPIPlugin
- AmplifyPlugins/AWSCognitoAuthPlugin
- AmplifyPlugins/AWSDataStorePlugin
SPEC REPOS:
trunk:
- Amplify
- AmplifyPlugins
- AppSyncRealTimeClient
- AWSAuthCore
- AWSCognitoIdentityProvider
- AWSCognitoIdentityProviderASF
- AWSCore
- AWSMobileClient
- AWSPluginsCore
- SQLite.swift
- Starscream
SPEC CHECKSUMS:
Amplify: 4cdf0631faffa42a47dc24affa6d84c555ca2f6a
AmplifyPlugins: dcf678f54171ce6d6367b79d5149bda5f47d9f9e
AppSyncRealTimeClient: 04df4dffe57cfbd06da336d0bfcd5641ba9adcb5
AWSAuthCore: 59770d4c2c1b3dbb183b95d1867e3584b4816e54
AWSCognitoIdentityProvider: 5bd6988ea7c8f9ee43151e19bdd8e803558ad45f
AWSCognitoIdentityProviderASF: 30ccb19228b6e743805bf15a72278ca9f399bc21
AWSCore: 70f79e95ee30f8eefa7122391d76ace516778f22
AWSMobileClient: 54fd215e76e34a8edb3cb1199788a69543cebc95
AWSPluginsCore: d4593ef79107b15a02597705b63c9c915a946ee9
SQLite.swift: d2b4642190917051ce6bd1d49aab565fe794eea3
Starscream: 4bb2f9942274833f7b4d296a55504dcfc7edb7b0
PODFILE CHECKSUM: 983d3172490a4f8f0c578d64c675b5952a4ad751
COCOAPODS: 1.10.0
Also with my own url session code I tried using access token and it didn't work, only id token did.
APIError: The HTTP response status code is [401].
Recovery suggestion: The metadata associated with the response is contained in the HTTPURLResponse.
For more information on HTTP status codes, take a look at
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
{"message":"Unauthorized"}
createUser operation myself:// in cognitoActions.js
async function createUser(username, name) {
const params = {
UserPoolId: userPoolId,
Username: username,
DesiredDeliveryMediums: ["EMAIL"],
UserAttributes: [
{"Name": "given_name", "Value": name},
{"Name": "email_verified", "Value": "true"},
{"Name": "email", "Value": username}
]
}
try {
const result = await cognitoIdentityServiceProvider.adminCreateUser(params).promise();
console.log(`Confirmed ${username} has been created`);
return {
message: `Confirmed ${username} has been created`
};
} catch (err) {
console.log(err)
throw err;
}
}
//in app.js
app.post('/createUser', async (req, res, next) => {
if (!req.body.username || !req.body.name) {
const err = new Error('username and name are required');
err.statusCode = 400;
return next(err);
}
try {
const response = await createUser(req.body.username, req.body.name);
res.status(200).json(response);
} catch (err) {
next(err);
}
});
Added the following permissions to AdminQueriesXXX-cloudformation-template.json
"cognito-idp:AdminCreateUser",
"cognito-idp:AdminDeleteUser"
This is something you can do as suggested by @undefobj in this cli issue here: https://github.com/aws-amplify/amplify-cli/issues/4351
Summary so far:
Next steps:
Next steps:
- Test in a configuration with multiple REST APIs and no GraphQL API, no DataStore
- Test in a configuration with multiple REST APIs and one GraphQL API, no DataStore
- Test in a configuration with one REST API and one GraphQL API linked to DataStore
- Test in a configuration with multiple REST APIs and one GraphQL API, linked to DataStore
- Make a new issue to fix Reachability implementation to work in multiple API configurations
I've updated the sample app here: https://github.com/lawmicha/adminAPI . I started off by modifying the lambda with the createUser functionality. When I ran amplify push, this reverted the manual changes done to amplifyconfiguration.json for the Admin API back to AWS_IAM and was confused why it was getting Unauthorized. After updating it back to AMAZON_COGNITO_USER_POOLS, things were working again and the new API was successful in creating users in the user pool. @kneekey23 coud you verify if the problem is the same for you?
I've also tested this out with DataStore and API configured, and then duplicated the REST API to have multiple REST APIs configured. Let me know if you are able to reproduce this from my sample app, otherwise we'll debug more in the context of your app.
For number 5, i've created an issue here: https://github.com/aws-amplify/amplify-ios/issues/1159
Discussed with @lawmicha offline and he will continue to investigate. Right now we are seeing a difference of tokens pulled by the library vs the mobile client and only one token actually works and is authorized by the API Gateway set up.
Just a short update, this is related to which token the plugin automatically pulls when intercepting the request.
Here's the format of the tokens using JWT.io
AccessToken:
{
"sub": "b2bb4867-d0e8-46f2-88ae-xxxxxxxxxx",
"cognito:groups": [
"Admin"
],
"event_id": "01c81570-e55f-43a2-a39f-xxxxxxxxxx",
"token_use": "access",
"scope": "aws.cognito.signin.user.admin",
"auth_time": 1618007469,
"iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-xxxxxxxxxx",
"exp": 1618251303,
"iat": 1618247703,
"jti": "37a1557c-5702-44ea-9e20-xxxxxxxxxx",
"client_id": "xxx",
"username": "xx"
}
IDToken
{
"sub": "b2bb4867-d0e8-46f2-88ae-xxxxxxxx",
"cognito:groups": [
"Admin"
],
"email_verified": true,
"iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-xxxxxxxx",
"cognito:username": "xxxxxx",
"cognito:roles": [
"arn:aws:iam::xxxxxxx:role/AdminQueries0f3fcc9fLambdaRole-dev"
],
"aud": "40aciuse3s6q1e6hn6kak7xxxxxx",
"event_id": "01c81570-e55f-43a2-a39f-xxxxxx",
"token_use": "id",
"auth_time": 1618007469,
"exp": 1618251303,
"iat": 1618247703,
"email": "[email protected]"
}
Using API Gateway, I am able to confirm that testing the Authorizer does return 401 for the Access token and success for the ID Token.
Why is working on my sample app and not @kneekey23 ?
I think the API Gateway's Authorizer Test functionality isn't a complete indication of what's happening. I noticed the request requires aws.cognito.signin.user.admin scope which should mean that the API Gateway request is accepting access token. I suspect there was a provisioning change in the CLI when provisioning the admin queries API but I'm not really sure.
I'll go ahead from a fresh start and see if I can discover something new about this.
path forward:
If the endpoint requires ID Token, then we can provide a custom interceptor like so: https://docs.amplify.aws/lib/restapi/authz/q/platform/ios#note-related-to-use-access-token-or-id-token
For the reachability issue, PR: https://github.com/aws-amplify/amplify-ios/pull/1167
For the token issue, since we know that the backend provisioning is what is different from our two Apps, please intercept the request with ID token: https://docs.amplify.aws/lib/restapi/authz/q/platform/ios#note-related-to-use-access-token-or-id-token
Regarding the link i pointed out for intercepting with an ID Token refers to configuring the user pool as an OPENID_CONNECT auth type. We discussed that this is also not ideal since the CLI will be provisioning it as user pools auth type. There is another way to add an inceptor to the existing interceptor chain, while keeping the auth type user pools, so for example:
After Amplify.configure(), call Amplify.API.add(interceptor:for:) with the API friendly name from amplifyconfiguration.json for that API
try Amplify.configure()
try Amplify.API.add(interceptor: MyCustomInterceptor(), for: "AdminQueries")
This will add an additional interceptor to the request interception chain. Then override the token value with the value you need to get it working, in this case, the tokens.idToken:
class MyCustomInterceptor: URLRequestInterceptor {
func getLatestAuthToken() -> Result<String, Error> {
let semaphore = DispatchSemaphore(value: 0)
var result: Result<String, Error> = .failure(AuthError.unknown("Could not retrieve Cognito token"))
Amplify.Auth.fetchAuthSession { (event) in
defer {
semaphore.signal()
}
switch event {
case .success(let session):
if let cognitoTokenResult = (session as? AuthCognitoTokensProvider)?.getCognitoTokens() {
switch cognitoTokenResult {
case .success(let tokens):
result = .success(tokens.idToken)
case .failure(let error):
result = .failure(error)
}
}
case .failure(let error):
result = .failure(error)
}
}
semaphore.wait()
return result
}
func intercept(_ request: URLRequest) throws -> URLRequest {
guard let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest else {
throw APIError.unknown("Could not get mutable request", "")
}
let tokenResult = getLatestAuthToken()
guard case let .success(token) = tokenResult else {
if case let .failure(error) = tokenResult {
throw APIError.operationError("Failed to retrieve Cognito UserPool token.", "", error)
}
return mutableRequest as URLRequest
}
mutableRequest.setValue(token, forHTTPHeaderField: "authorization")
return mutableRequest as URLRequest
}
}
Since @kneekey23's admin queries API was provisioned with AWS_IAM, and updates will always override it to that, i'd suggest creating another API configuration under awsAPIPlugin as
"plugins": {
"awsAPIPlugin": {
"AdminQueries": {
"endpointType": "REST",
"endpoint": "https://xxx123.execute-api.us-west-2.amazonaws.com/dev",
"region": "us-west-2",
"authorizationType": "AWS_IAM" // CLI keeps overriding
},
"AdminQueries2": { // new config where CLI does not touch
"endpointType": "REST",
"endpoint": "https://xxx123.execute-api.us-west-2.amazonaws.com/dev",
"region": "us-west-2",
"authorizationType": "AMAZON_COGNITO_USER_POOLS" // keep this as user pools
},
then remember to update the interceptor to override the "AdminQueries2" API try Amplify.API.add(interceptor: MyCustomInterceptor(), for: "AdminQueries2")
Update: Turns out, CLI updates also removes the "AdminQueries2" api, I had thoughht additive changes do not get overriden by the CLI. If this is true, then there might be a bug here, otherwise, the extra API also gets removed and updating the authorizationType after every update might be the simplest path forward
draft PR related to None authorization type, and will put the example interceptor there https://github.com/aws-amplify/docs/pull/3210