Open lawmicha opened 4 years ago
@lawmicha thanks for opening the issue, I see the customer need here and this is something the CLI could support out of the box. I take this to the team for discussion and get back to you.
I agree this is really important. API+Lambda+Cognito did not work out of the box for me!
I need this feature. Cognito User Pool Authorization provides us to powerful and useful permission management.
I spent hours banging my head on this and went through multiple tutorials and digging through code. Thank you for such a great walk-thru and this needs to be added!
Great walk through. Thanks a lot. Hope this automation is added soon. for such an important feature. It is essentially the same as AdminQueries API. It should be easy for the Amplify team to copy what has done over.
@lawmicha I wondered if something may have changed or if perhaps a step is missing. I have tried a couple times, at first with the auth I already had set up and the removed all the api, functions & auth and tried again and it doesn't seem to generate amplifyconfiguration.json
. Where do you see that file generated? I've also tried searching for plugins
and authorizationType
I apologize if I am just missing it some how.
I had previously tried manually adding the Cognito Authorizer in another project and realized when I ran push again for some changes the Authorizer got trashed, so I'm hoping this will solve that. Thanks for any info you can provide.
@lawmicha I wondered if something may have changed or if perhaps a step is missing. I have tried a couple times, at first with the auth I already had set up and the removed all the api, functions & auth and tried again and it doesn't seem to generate
amplifyconfiguration.json
. Where do you see that file generated? I've also tried searching forplugins
andauthorizationType
I apologize if I am just missing it some how.
Hi @smakinson, amplifyconfiguration.json
is used in iOS and Android projects. Sorry I should have clarified. Are you using Amplify CLI with your JS app? (amplify init
-> which type of project). I believe JS should be aws_exports.json or something
I had previously tried manually adding the Cognito Authorizer in another project and realized when I ran push again for some changes the Authorizer got trashed, so I'm hoping this will solve that. Thanks for any info you can provide.
This sounds like expected behavior but also a problem if amplify push
reverts any manual changes done through AWS Console. If confirmed, then is it supported to modify the cloud formation templates ourselves after using Amplify CLI that will not get overwritten after another amplify push
?
@lawmicha Thanks for your response, you are correct, it is a javascript project. Hoping to find a way around it losing the Authorizer within Amplify.
aws-exports.js
shows:
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
so it seems that is not the file I want. I'll keep digging.
@smakinson aws-exports.js
will be reverted after amplify push
. So maybe the APIGateway still has the authorizer set up but the configuration file in the app is reverted. this will be same issue with amplifyconfiguration.json
. You can also programmatically configure Amplify.API without using aws-exports.js
, although that will mean you need to transfer all the values over to code, and configure Amplify.Auth programmtically and any other categories you have as well
I just want to note that this is a feature request, and not necessarily steps for developers to follow and get working, they are steps provided to assist in turning this into an Amplify CLI feature. Following these steps are not supported by Amplify CLI. As we've seen the issue with the configuration file being overwritten.
@lawmicha Incase this is helpful for others I thought I'd post up here what I am looking at doing with the cloudformation template, and if you have a moment I have 2 questions, one general and the other (without taking too much of your time) if you might know the fix for an error:
Do you know at what point backend-config.json
and the myApi-cloudformation-template.json
gets overwritten and if I will lose any manual changes there? Kinda making this still risky if changes are easily lost...so is this even a good idea?
I have it working if I hardcode my POOL ARN in the last bit of this and I'm trying to change now to get it based on the current environment based on https://aws-amplify.github.io/docs/cli-toolchain/quickstart#custom-cloudformation-stacks Since I'm editing an existing resource I think a few steps aren't relevant, but I have modified backend-config.json
by adding an additional item to the dependsOn
array for the REST api, added:
"myApi": {
"service": "API Gateway",
"providerPlugin": "awscloudformation",
"dependsOn": [
{
"category": "function",
"resourceName": "myFunc",
"attributes": [
"Name",
"Arn"
]
},
{
"category": "auth",
"resourceName": "myAuthResource", // from amplify status
"attributes": [
"UserPoolId"
]
}
]
}
in the Parameters
section of the myApi-cloudformation-template.json
added:
"authmyAuthResourceUserPoolId": { // The format out here is `<category><resource-name><attribute-name>
"Type": "String"
}
the methods have the authorizer attached by adding the following under x-amazon-apigateway-any-method
"security": [
{
"CognitoAuthorizer": []
}
],
and further down in the file I'm trying to reference it like:
"securityDefinitions": {
"CognitoAuthorizer": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"x-amazon-apigateway-authtype": "cognito_user_pools",
"x-amazon-apigateway-authorizer": {
"providerARNs": [
{
"authmyAuthResourceUserPoolId": { // The format out here is `<category><resource-name><attribute-name>
"Fn::GetAtt": [
"authmyAuthResource", // I've tried this with and without the auth category prefix
"Outputs.UserPoolId"
]
}
}
],
"type": "cognito_user_pools"
}
}
}
Next I ran amplify env checkout CURRENT_ENV
and then amplify push
The error in question is the one I see when I run amplify-push
:
Template error: instance of Fn::GetAtt references undefined resource authmyAuthResource
Maybe I'm just mistyping something, hopefully this can be helpful for anyone in a javascript amplify project until the cli supports it. Thanks for any insight.
Thanks @smakinson for posting your details. I'm not very familar with those files you are asking about in your questions. + @SwaySway et al to help answer
Hello @smakinson,
Your API specific changes in backend-config.js
and myApi-cloudformation-template.json
are changed when you run amplify update API
.
I have it working if I hardcode my POOL ARN in the last bit of this and I'm trying to change now to get it based on the current environment based on https://aws-amplify.github.io/docs/cli-toolchain/quickstart#custom-cloudformation-stacks
The docs here specify a way to get the user pool id into another stack. What you are looking for is the UserPoolArn. For that you'll need to import will be different, I've detailed this below.
You'll need to use a different ref for the ARN such as "Ref": "authMyAuthResourceNameUserPoolArn"
and add that as a parameter in the template.
"authMyAuthResourceNameUserPoolArn": {
"Type": "String"
}
In parameters.json
you'll need to point to the auth stack to reference the UserPoolArn
"authMyAuthResourceNameUserPoolArn": {
"Fn::GetAtt": [
"MyAuthResourceName",
"Outputs.UserPoolArn",
"Arn"
]
}
Currently arn is not included in the outputs of the auth stack, this is something we can consider as a part of this feature request. For this you'll want to export the Arn as well from the auth stack.
UserPoolArn:
Value: !GetAtt UserPool.Arn
Description: Arn for cognito userpool
The last thing here to edit would be to change the backend-config.json
to denote that the api resource depends on the auth stack.
"api": {
"demorest": {
"service": "API Gateway",
"providerPlugin": "awscloudformation",
"dependsOn": [
{
"category": "function",
"resourceName": "demoRestFN",
"attributes": [
"Name",
"Arn"
]
},
{
"category": "auth",
"resourceName": "MyAuthResourceName",
"attributes": [
"UserPoolArn"
]
}
]
}
}
All that's left here is to run amplify env checkout <current-env-name>
and amplify push
.
@SwaySway Thank you for your help. I currently have manually setup an api for this, do you think its worth (risky?) going this route or would it be better to wait on the feature request and change it then?
This is a great workaround for now for creating Cognito Authorizers. Perhaps in a similiar vein, Is it safe to edit lambdaFunction-cloudformation-template.json? When does it get overwritten ? If I needed to add custom resources (ie a lambda policy), is the recommended approach to modify this cfn template ? Im looking for an analogy to the CustomResources.json template in the api/stacks folder.
I'm trying to accomplish the same thing (calling API GW with Cognito Auth) and made it work with above method.
However: my call only succeeds if I use an ID Token to authenticate:
let init = {
headers: { Authorization: `Bearer ${(await Auth.currentSession()).getIdToken().getJwtToken()}` }
}
API.get('xxx', '/items', myInit).then( result => {
console.log(result);
})
It's not working with an access token:
let init = {
headers: { Authorization: `Bearer ${(await Auth.currentSession()).getAccessToken().getJwtToken()}` }
}
API.get('xxx', '/items', myInit).then( result => {
console.log(result);
})
Fails with 401 and body { "message" : "unauthorized"}
I'd expect an access token to work instead of an id token. Is there anything I'm doing wrong?
What's the latest status on this?
Been scratching my head for hours trying to figure out why this was not working out of the box. The latest CLI makes you go through steps to set it all up, but does not build a CloudFormation template that actually works.
Again, it is blowing my mind how often I have to fix this stuff myself in vs having the Amplify CLI do what it is supposed to do. Does the Amplify product team not have any QA engineers?
I got this working using @lawmicha 's steps and @jwoehrle 's code. To my understanding, I'm going to have to follow these steps every time we deploy (though I haven't tested this part yet). Is there any other workaround that will work automatically?
Edit: It is working well, but does require this configuration to be set every time the API is updated from the amplify CLI.
Any news on getting this implemented? Overriding the amplify config manually is a time-consuming process for a feature that should already be there.
I'm trying to accomplish the same thing (calling API GW with Cognito Auth) and made it work with above method.
However: my call only succeeds if I use an ID Token to authenticate:
let init = { headers: { Authorization: `Bearer ${(await Auth.currentSession()).getIdToken().getJwtToken()}` } } API.get('xxx', '/items', myInit).then( result => { console.log(result); })
It's not working with an access token:
let init = { headers: { Authorization: `Bearer ${(await Auth.currentSession()).getAccessToken().getJwtToken()}` } } API.get('xxx', '/items', myInit).then( result => { console.log(result); })
Fails with 401 and body
{ "message" : "unauthorized"}
I'd expect an access token to work instead of an id token. Is there anything I'm doing wrong?
Here's from the documentation.
With the COGNITO_USER_POOLS authorizer, if the OAuth Scopes option isn't specified, API Gateway treats the supplied token as an identity token and verifies the claimed identity against the one from the user pool. Otherwise, API Gateway treats the supplied token as an access token and verifies the access scopes that are claimed in the token against the authorization scopes declared on the method.
My last comment got deleted, pretty good Team.
Is this being worked on? This seems like a very important feature and i was surprised when it did not work out of the box. Have been trying to solve an issue for some hours now and stumbled upon this now
This would be a very useful feature! For now, we have to set the authorizer for all resources after every "amplify update api", because amplify overwrites the template file : (
I love Amplify, and this is a feature that I’d very much like to see implemented, like the many others in this thread :) could you please share any status updates, dear Amplify Team?
I've also just come across this issue. My first thought was to simply update the generated cloudformation file, however... the template used by the CLI to generate the CloudFormation config is located here:
In your generated API folder, e.g. amplify/backend/api/myapi
there'll be another file called api-params.json
which I believe is used to control the template generation process. e.g. running amplify update api
will update the params and then re-generate the CloudFormation file. This explains why any update
commands will re-generate the cloudformation file and overwrite any changes you've made.
My second thought is to somehow define cloudformation customizations in a separate file, and then somehow hook into the amplify push
process to merge the customizations into the generated template. If anyone is keen to help me look, let me know!
Hi, is there any roadmap for this feature request? I also face this issue. IMO, it is a fundamental feature (API-Gateway authentication using Cognito User Pool) and it should be supported. What is the point of creating API-Gateway and Cognito, both by Amplify CLI, but cannot use them together?
Thanks.
Here's what I did to add the Custom Authorizer to the API's CloudFormation template.
It's worth noting that AdminQueries
has COGNITO_USER_POOLS Authorizer, so I copy-pasted parts of the template there.
Add securityDefinitions
to your API name properties ( Resources > <API name> > Properties
)
Example:
"securityDefinitions": {
"Cognito": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"x-amazon-apigateway-authtype": "cognito_user_pools",
"x-amazon-apigateway-authorizer": {
"providerARNs": [
{
"Fn::Join": [
"",
[
"arn:aws:cognito-idp:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":userpool/",
{
"Ref": "<your_user_pool>"
}
]
]
}
],
"type": "cognito_user_pools"
}
}
},
This defines the Custom Authorizer called "Cognito" that's based on your user pool. <your_user_pool>
should then be added to the CF's template parameters: (Top level > Parameters, just below env
and authRoleName
/unauthRoleName
)
"<your_user_pool>": {
"Type": "String",
"Default": "<your_user_pool>"
},
This validates the Ref
created through securityDefinitions
. Finally, add this to the paths > x-amazon-apigateway-any-method
(for ANY) and for all paths:
parameters
:
{
"name": "Authorization",
"in": "header",
"required": false,
"type": "string"
}
Top level (inside paths
):
"security": [
{
"Cognito": []
}
],
Note that Cognito accepts an array of OAuth scopes, mine's empty. AdminQueries has aws.cognito.signin.user.admin
as an OAuth scope.
I'm guessing this follows the same logic as https://github.com/aws-amplify/amplify-cli/issues/4351 , a manual adding of permissions to the policy, which can be pushed to a project. I tried using amplify pull
on a separate branch and the CF edits stuck. I haven't tried amplify pull
on a separate project though that shares the amplify configuration.
Setting this up was a bit unclear for me, but eventually I got it through a combination of @brymartinez and @SwaySway post's. Thanks for that!
This consolidates those posts into one to make it easier for future dwellers to implement this functionality.
The following will apply to the JavaScript Amplify library.
Set up the appropriate parameters coming into your REST API's CloudFormation (CF) template. This is found in: ./amplify/backend/api/<the name of your api>/parameters.json
.
From my guess this file acts as a way for the backend resources to pass values to each other just as long as they have been set in the resources CF template Outputs
key.
Add the following key/value after whatever key/values are there already or within the empty object. For me this was an empty file, but for you it could have preexisting values. You'll find name for auth
in ./amplify/backend/backend-config.json
under the "auth"
key.
You'll have to check the ./amplify/backend/auth/<the name of your auth>/<name of your auth>-cloudformation-template.yml
to see if UserPoolId
is being outputted. I'd be surprised if it wasn't.
AuthCognitoUserPoolId
is a descriptive name I gave it. This will be used in the next step as reference to the UserPoolId
.
"AuthCognitoUserPoolId": {
"Fn::GetAtt": ["auth<name for auth>", "Outputs.UserPoolId"]
}
Set up the appropriate Parameters
, securityDefinitions
, security
, and parameter
values in your REST API's CF template. This is found in ./amplify/backend/api/<the name of your api>/<the name of your api>-cloudformation-template.json
.
In the "Parameters"
key add the following key/value:
"AuthCognitoUserPoolId": {
"Type": "String",
"Description": "The id of an existing User Pool to connect. If this is changed, a user pool will not be created for you.",
"Default": "NONE"
},
In "Resources" > "<your api name>" > "Properties" > "Body"
add the following key/value. This is creating the authorizer and the AuthCognitoUserPoolId
parameter is being used her to reference the Cognito user pool you want to use.
I originally thought AuthCognitoUserPoolId
was the literal user pool id value, but I got an error when I added that as the key for the parameter.
The "Cognito"
key is a custom name and you can name it anything.
"securityDefinitions": {
"Cognito": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"x-amazon-apigateway-authtype": "cognito_user_pools",
"x-amazon-apigateway-authorizer": {
"type": "cognito_user_pools",
"providerARNs": [
{
"Fn::Join": [
"",
[
"arn:aws:cognito-idp:",
{
"Ref": "AWS::Region"
},
":",
{
"Ref": "AWS::AccountId"
},
":userpool/",
{
"Ref": "AuthCognitoUserPoolId"
}
]
]
}
]
}
}
},
In "Resources" > "<your api name>" > "Properties" > "Body" > "paths" > "<your path/s name>" > "x-amazon-apigateway-any-method" > "parameters"
add the following key/value to the array. This is defining the Authorization
header as a parameter that has the token.
This has to be added to all of the methods to which you want to apply this authorization. It will be under the appropriate http method key such as "get", "post", etc. I didn't apply it to "options"
because it's not needed.
{
"name": "Authorization",
"in": "header",
"required": false,
"type": "string"
}
In "Resources" > "<your api name>" > "Properties" > "Body" > "paths" > "<your path/s name>" > "x-amazon-apigateway-any-method" > "security"
add the following key/value. Like the parameter above it needs to be added to any methods you want this authorization to apply. This has to be the same as the name you gave the key in the "securityDefinitions"
object.
This will select this authorizor for the method. If it's not added when you go into the API Gateway console and select the method you'll see NONE in the Auth setting even though the Cognito authorizer has been setup and is an option in the dropdown menu.
For anything other than OAuth2 type security scheme this must be empty.
"security": [
{
"Cognito": []
}
],
That's it for the implementation of the infrastructure. Run amplify push
to set it all up.
From what I can tell the configuration setup doesn't get overridden with updates. But I've not thoroughly tested it.
For usage, this is what I'm doing:
import { API, Auth } from 'aws-amplify'
....
const apiName = '<your api name>'
const path = '/<your api path>'
const myInit = {
body: {
test: 'test'
},
headers: {
Authorization: `Bearer ${(await Auth.currentSession())
.getIdToken()
.getJwtToken()}`
},
response: true,
queryStringParameters: {}
}
const finaliseImportResp = await API.post(apiName, path, myInit)
For reference here's some AWS documentation:
From my experience working with Amplify when I run amplify api add
and I go through and choose express backend```` I am unable to update the AGW's. Firstly, I can't make any changes to
Access-Control-Allow-Headers```. Secondly, I am unable to send my Access Token so I can crack it in the Express Backend function (which could be more control over what a user can/can't do). Additionally, if we follow the documentation's on sending access/id tokens we are unable to get that data pass the AGW even though it's suggested in the documentation. Having this handled from the cli would be easier for other devs.
Setting this up was a bit unclear for me, but eventually I got it through a combination of @brymartinez and @SwaySway post's. Thanks for that!
This consolidates those posts into one to make it easier for future dwellers to implement this functionality.
The following will apply to the JavaScript Amplify library.
STEP 1
Set up the appropriate parameters coming into your REST API's CloudFormation (CF) template. This is found in:
./amplify/backend/api/<the name of your api>/parameters.json
.From my guess this file acts as a way for the backend resources to pass values to each other just as long as they have been set in the resources CF template
Outputs
key.Add the following key/value after whatever key/values are there already or within the empty object. For me this was an empty file, but for you it could have preexisting values. You'll find
name for auth
in./amplify/backend/backend-config.json
under the"auth"
key.You'll have to check the
./amplify/backend/auth/<the name of your auth>/<name of your auth>-cloudformation-template.yml
to see ifUserPoolId
is being outputted. I'd be surprised if it wasn't.
AuthCognitoUserPoolId
is a descriptive name I gave it. This will be used in the next step as reference to theUserPoolId
."AuthCognitoUserPoolId": { "Fn::GetAtt": ["auth<name for auth>", "Outputs.UserPoolId"] }
STEP 2
Set up the appropriate
Parameters
,securityDefinitions
,security
, andparameter
values in your REST API's CF template. This is found in./amplify/backend/api/<the name of your api>/<the name of your api>-cloudformation-template.json
.In the
"Parameters"
key add the following key/value:"AuthCognitoUserPoolId": { "Type": "String", "Description": "The id of an existing User Pool to connect. If this is changed, a user pool will not be created for you.", "Default": "NONE" },
In
"Resources" > "<your api name>" > "Properties" > "Body"
add the following key/value. This is creating the authorizer and theAuthCognitoUserPoolId
parameter is being used her to reference the Cognito user pool you want to use.I originally thought
AuthCognitoUserPoolId
was the literal user pool id value, but I got an error when I added that as the key for the parameter.The
"Cognito"
key is a custom name and you can name it anything."securityDefinitions": { "Cognito": { "type": "apiKey", "name": "Authorization", "in": "header", "x-amazon-apigateway-authtype": "cognito_user_pools", "x-amazon-apigateway-authorizer": { "type": "cognito_user_pools", "providerARNs": [ { "Fn::Join": [ "", [ "arn:aws:cognito-idp:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":userpool/", { "Ref": "AuthCognitoUserPoolId" } ] ] } ] } } },
In
"Resources" > "<your api name>" > "Properties" > "Body" > "paths" > "<your path/s name>" > "x-amazon-apigateway-any-method" > "parameters"
add the following key/value to the array. This is defining theAuthorization
header as a parameter that has the token.This has to be added to all of the methods to which you want to apply this authorization. It will be under the appropriate http method key such as "get", "post", etc. I didn't apply it to
"options"
because it's not needed.{ "name": "Authorization", "in": "header", "required": false, "type": "string" }
In
"Resources" > "<your api name>" > "Properties" > "Body" > "paths" > "<your path/s name>" > "x-amazon-apigateway-any-method" > "security"
add the following key/value. Like the parameter above it needs to be added to any methods you want this authorization to apply. This has to be the same as the name you gave the key in the"securityDefinitions"
object.This will select this authorizor for the method. If it's not added when you go into the API Gateway console and select the method you'll see NONE in the Auth setting even though the Cognito authorizer has been setup and is an option in the dropdown menu.
For anything other than OAuth2 type security scheme this must be empty.
"security": [ { "Cognito": [] } ],
That's it for the implementation of the infrastructure. Run
amplify push
to set it all up.From what I can tell the configuration setup doesn't get overridden with updates. But I've not thoroughly tested it.
For usage, this is what I'm doing:
import { API, Auth } from 'aws-amplify' .... const apiName = '<your api name>' const path = '/<your api path>' const myInit = { body: { test: 'test' }, headers: { Authorization: `Bearer ${(await Auth.currentSession()) .getIdToken() .getJwtToken()}` }, response: true, queryStringParameters: {} } const finaliseImportResp = await API.post(apiName, path, myInit)
For reference here's some AWS documentation:
@johnEthicalTechnology Thank you so much for this. Could you also explain how to restrict the api access?
The above solution no longer works due to some changes in how cloud formation templates are generated / overridden in AWS Amplify (which is now done with CDK instead of directly modifying the cloud formation template). I threw together a gist for an override.ts
file which should be put in your API folder instead as an update to the wonderful solution put together by @johnEthicalTechnology:
https://gist.github.com/evankirkiles/9de81f026a2e2c961a2b6a3d80d35519
Feel free to recommend changes!
The above solution no longer works due to some changes in how cloud formation templates are generated / overridden in AWS Amplify (which is now done with CDK instead of directly modifying the cloud formation template). I threw together a gist for an
override.ts
file which should be put in your API folder instead as an update to the wonderful solution put together by @johnEthicalTechnology:https://gist.github.com/evankirkiles/9de81f026a2e2c961a2b6a3d80d35519
Feel free to recommend changes!
@evankirkiles Thanks for sharing! Your gist worked great for me.
Hello, I've used this manual to configure Cognito User Pool authorizer, but during the deployment, I'm getting this error:
Resource Name: 1rfy2sfng2 (AWS::ApiGateway::RestApi)
Event Type: update
Reason: Errors found during import:
Unable to create authorizer 'Cognito': ProviderARNs need to be valid Cognito Userpools. Invalid ARNs-
arn:aws:cognito-idp:{AWS::Region}:{AWS::AccountId}:userpool/{AuthCognitoUserPoolId}
Unable to put method 'x-amazon-apigateway-any-method' on resource at path '/invite/verify': Invalid authorizer ID specified. Setting the authorization type to CUSTOM or COGNITO_USER_POOLS requires a valid authorizer.
Unable to put method 'x-amazon-apigateway-any-method' on resource at path '/invite/verify/{proxy+}': Invalid authorizer ID specified. Setting the authorization type to CUSTOM or COGNITO_USER_POOLS requires a valid authorizer. (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 0ef6e1aa-3d3f-4d45-990b-e41b21ad64f8; Proxy: null)
I did not forget to replace your auth name here :) Any thoughts?
And one more question, we can make the function private from CLI. Then, there is information about the user in event.requestContext.identity. Why not use it?
shit, every time I add new API path I need to recreate the Authorizer & redeploy the api
kinda a pain when quickly prototyping project
:(
Hi @shkomg I'm experiencing exactly the same problem. If override I get the same errors @sshvaiko had.
UPDATE:
ARNs- arn:aws:cognito-idp:{AWS::Region}:{AWS::AccountId}:userpool/{AuthCognitoUserPoolId}
doesn't update variables. So you should manually modify the values: AWS::Region, AWS::AccountId; AuthCognitoUserPoolId. 😄 😄 😄
It effectively works using Amplify-CLI 9.1.0 but in my opinion could lead to security issues. Workarounds could be to modify the script or to add a env. var. for example.
Hi @rondondaniel I definitely expect it working out of the box with default CLI prompts and waiting for Amplify team to resolve this. Meanwhile for me updating over the API Gateway once in while isn't perfect but Ok. It just simpler to remember VS changes in code, at least for me :)
@sshvaiko @rondondaniel no need to manually update the values. That's the whole idea of the script, right :|
I believe the documentation is just wrong and you should put $
before the {...}
substitutions, like { "Fn::Sub": "arn:aws:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/${AuthCognitoUserPoolId}" }
I had the same issue as @shkomg and @rondondaniel.
@rafhuys-klarrio fix (adding the $'s ) worked for me.
It is pretty bad that Amplify does not support this out of box
In a word, there are 3 steps to achieve this. Ref: https://docs.amplify.aws/cli/restapi/override/#add-a-cognito-user-pool-authorizer-to-your-rest-api
Step1:
$ amplify override api
Step2:
edit amplify/backend/api/yourProject/override.ts
export function override(resources: AmplifyApiRestResourceStackTemplate) {
// Add a parameter to your Cloud Formation Template for the User Pool's ID. The name of resource is the name of the folder in amplify/backend/auth
resources.addCfnParameter({
type: "String",
description: "The id of an existing User Pool to connect. If this is changed, a user pool will not be created for you.",
default: "NONE",
},
"AuthCognitoUserPoolId",
{ "Fn::GetAtt": ["auth<YourAuthSetting>", "Outputs.UserPoolId"], }
); // YourAuthSetting can be found `ls amplify/backend/auth`
// Create the authorizer using the AuthCognitoUserPoolId parameter defined above
resources.restApi.addPropertyOverride("Body.securityDefinitions", {
Cognito: {
type: "apiKey",
name: "Authorization",
in: "header",
"x-amazon-apigateway-authtype": "cognito_user_pools",
"x-amazon-apigateway-authorizer": {
type: "cognito_user_pools",
providerARNs: [
{ 'Fn::Sub': 'arn:aws:cognito-idp:${AWS::Region}:${AWS::AccountId}:userpool/${AuthCognitoUserPoolId}' },
],
},
},
});
// For every path in your REST API
for (const path in resources.restApi.body.paths) {
if (path.startsWith('/somepath')) {
console.log('Skip the path not to use Authorization header', path);
continue;
}
console.log('Make the path for restapi to have Authorization', path);
// Add the Authorization header as a parameter to requests
resources.restApi.addPropertyOverride(
`Body.paths.${path}.x-amazon-apigateway-any-method.parameters`,
[
...resources.restApi.body.paths[path]["x-amazon-apigateway-any-method"]
.parameters,
{
name: "Authorization",
in: "header",
required: false,
type: "string",
},
]
);
// Use your new Cognito User Pool authorizer for security
resources.restApi.addPropertyOverride(
`Body.paths.${path}.x-amazon-apigateway-any-method.security`,
[ { Cognito: [], }, ]
);
}
}
Step3: Update config applying the above CloudFormation
amplify push
Again, it is blowing my mind how often I have to fix this stuff myself in vs having the Amplify CLI do what it is supposed to do. Does the Amplify product team not have any QA engineers?
I have the same experience and the same frustrations. I think it has less to do with the product team than what I expect is a disconnect between how executives have positioned Amplify, and what the team is actually resourced and directed to do. Mismanagement in other words.
It has been 3 years since this feature was requested and no updates yet. It is very disappointing to see the Amplify team not taking any action on this.
It has been 3 years since this feature was requested and no updates yet. It is very disappointing to see the Amplify team not taking any action on this.
As near as I can tell Amplify is dead. The whole thing is riddled with fatal bugs that eventually crop up and wreck you project. I regret ever using it.
Still not fixed.
OMG just came to add a simplay lambda with Cognito auth and see the hoops you've got to jump through. What a pile of junk
OMG just came to add a simplay lambda with Cognito auth and see the hoops you've got to jump through. What a pile of junk
Nothing in my software experience has wasted more of my time than Amplify. Use Heroku.
I can suggest an easier solution for NodeJS, you can use this library https://github.com/awslabs/aws-jwt-verify in the lambda function itself. Initializer: const verifier = CognitoJwtVerifier.create({ userPoolId: process.env.COGNITO_USER_POOL_ID, tokenUse: "id", clientId: process.env.COGNITO_CLIENT_ID, }); Verifier: try { await verifier.verify(event.headers.Authorization) } catch { return { statusCode: 401, body: "Unaothorized!", }; }
Hi guys, for who are still looking for solutions of adding authorizers, here's the link I found in the amplify doc, which shows how to add cognito user pool authorizer or custom lambda authorizer : https://docs.amplify.aws/javascript/build-a-backend/restapi/override-api-gateway/
Is your feature request related to a problem? Please describe. Amplify CLI provides a way to create a REST api (API Gateway + lambda) with IAM authorization. in the JS docs, there are manual steps to add cognito user pool as the authorizator for the requests to API gateway: https://aws-amplify.github.io/docs/js/api#cognito-user-pools-authorization (however, this could be improved, see step 11 below). Amplify iOS (https://github.com/aws-amplify/amplify-ios/pull/312) and Android also supports this API with user pools as the auth mechanism.
The pain point is here is that Amplify CLI doesn't support creating API Gateway + Cognito User Pool authorizator. I'm opening this issue here to provide more details around what needs to done to enable API Gateway with Cognito.
The following steps show how to set up an API endpoint with APIGateway and Lambda source. The auth configured will be Cognito User Pool.
Initialize an amplify project.
amplify init
Create an API Gateway which proxies requests to an AWS Lambda with no authorization needed.
amplify add api
.Create Cognito User Pool. Run
amplify add auth
Provision the resources. Run
amplify push
to provision the API Gateway, Lambda, and the Cognito User Pool.In
amplifyconfiguration.json
. updateauthorizationType
toAMAZON_COGNITO_USER_POOLS
like soFind your API name. Run
amplify console
to open the AWS Console. The latest deployment activty logs will indicate the API Gateway that is provisioned. There will be a Resource ID that looks like<api name> (api)
. Navigate to API Gateway console, select your API.Find your Cognito User Pool name by click on the Authentication tab in the AWS Console.
Add Cognito User Pool as an authorization mechanism. Select Authorizers, click on "+ Create New Authorizer",
Cognito
as the typeAuthorization
Enable requests to the API with the Cognito User Pool Authorizer as the authorization mechanism.
Any
. You will see a Test section, Method Request, Method Response, Integration Request, etcThere are some additional gotcha's that need to be noted here:
amplify push
, so developer will need to programmatically instantiate Amplify.Describe the solution you'd like A clear and concise description of what you want to happen.
amplify add api
Alternatives JS docs could use some improvements with step number 11, for example it doesn't guide the develop to re-deploy the API. iOS and Android Amplify docs will be written simiarly.
Dedupped to https://github.com/aws-amplify/amplify-cli/issues/3058 aws-amplify/amplify-category-api#438 (Just realized this one is for API + API Key, not user pool)