Give Azure WebJob access to AppService's [Authorize] API - azure-webjobs

I have a AppService that has an API controller that requires authentication. I also have a WebJob on the AppService. The WebJob is trying to call an endpoint on the API but is required to authenticate to succeed. When the API controller is not marked as [Authorize], then the WebJob successfully calls the API endpoint anonymously. I have tried to use DefaultAzureCredential but I get an exception: DefaultAzureCredential authentication failed. So maybe I cannot use DefaultCredentials for this?
I could create an authorised account and store the username and password in KeyVault and have my WebJob use those to authenticate (I have verified the webjob can access my KeyVault). Is that the only option I have or is there a proper way to do this?

Related

What is the best way to authorize an AWS API call for a logged in user?

I have a spring boot based web application which already authenticates the user. I would like to create some AWS APIs using AWS api gateway and a springboot rest app deployed on EC2. The user will log into the existing application and call the new AWS APIs from the browser ajax calls (like an SPA I guess but I have a server and can use client credentials/secrets if needed). What is the best way to handle security for the APIs. My first thought was to generate a JWT using a shared server side secret for hash and verify it with an AWS lambda. But this seems a bit non standard. Oauth2 might be better but might also be over kill. Not sure the performance would be good. Few requirements
token passed to the API should be a user specific token and have an expiration (and hence a refresh token)
The user is already logged into my web app and calling the api should not issue a login challenge.
AWS API Gateway should be able to verify the token before passing it to the application
Any token passed to the API should probably be generated on the logged in web application. Server knows the user is authenticated and should generate the user access token on behalf of the user. The AWS api should be able to figure out what privileges the user has based on the user principle or scopes in the token
I've thought about using Cognito AWS but I dont want to require the users to preexist in a user pool. Cognito seems geared more for the authentication rather than authorization and I would not be using the cognito login functionality. I dont know if its possible to use the oauth2/token endpoint alone with cognito.

Testing Cognito user pool auth with API gateway

I would like my client application to insert records in my dynamoDb instance using API gateway secured with Cognito user pools.
I have created my user pool and added it as an authorizer to my API gateway method call. Using AWS Cli I ran the following command which gave me my access token:
aws cognito-idp initiate-auth ...
My infrastructure seems to be working, now which direction do I need to go to pragmatically achieve signing-in as my user in the user pool, grabbing the token and calling my API method?
Well it's not difficult. You need to follow certain steps.
Create an user in Cognito user pool. Confirm it, by the means of activation message you have chosen. It can be sms or email as per the user pool settings.
After you confirm the user, you need to call the login API from Cognito SDK. Since I am comfortable in NodeJS, let me grab the method name - https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html. Set AuthFLow to ADMIN_NO_SRP_AUTH .The response from this APi will have one idToken, one accessToken and one refreshToken. Since you need these credentials at your client, write an API in your preferred language, expose it your client and return the tokens.
Use the idToken to make API calls to your API Gateway Authorizer. This is how you pass the token using Postman -
You can replicate the same using any client. If you face any error, It'd be better if you show me your APIG authorizer configuration.

How can I use Cognito OAuth 2.0 to authenticate a API Gateway request without having an app client secret?

I'm using aws sdk to manage logins and signups on my app and the sdk requires my app client to have no secret key. This is a problem since I intend to use Cognito to authenticate the API gateway. I tried to enable OAuth 2.0 client credentials flow on app client settings, select a scope and give it to the API method, but when I try to save the app client settings I get:
"We were unable to update your App Configuration: client_credentials flow can not be selected if client does not have a client secret. (Service: AWSCognitoIdentityProviderService; Status Code: 400; Error Code: InvalidOAuthFlowException"
Is there a better way to configure API Gateway with Cognito? Am I doing something wrong?
You need to create a new app client for your API with a secret.
front end client - app client with out secret
Backend client / api - app client with secret
Client credentials is a usually a method for service-service authentication. You have to store the secret securely.therefore insecure to use in an unsafe front end app such as an html website.
Hope this helps.
To add to Arun's answer, the API should not need a Cognito OAuth client entry and just needs to validate received Cognito access tokens.
Typically this is done by downloading JWKS keys from Cognito - and API Gateway has a setting that automatically does this.
I can provide further details if you run into problems identifying the user after token validation.

Using AWS Amplify authenticated user to communicate with an ALB or API Gateway?

I set up my AWS Cognito integration into my React Native app using amplify add auth according to the guide, all is well and good, I'm able to register and login in the app. The cli wizard associates two app clients with the User Pool it creates: [poolid]_app_client and [poolid]_app_clientWeb.
I would like to have authenticated users be able to communicate with a web app hosted on an EC2 instance. I thought I could use an Application Load Balancer to do this by setting it up to forward authenticated requests to the EC2 instance. Problem is, I'm unable to create an Application Load Balancer default action that authenticates with the Cognito User Pool.
If I choose the App Client associated with the [poolid]_app_clientWeb, I get an error on save: Error creating listener The user pool client must have a client secret. This is the client ID exported by the amplify tools to my React Native app in aws-exports.js.
If I choose the App Client associated with the [poolid]_app_client I get Error creating listener OAuth flows must be enabled in the user pool client.
Not sure how to proceed. Is ALB the way to go or API Gateway?
You should have made appropriate changes in "User Pools -> App Integration -> App client" settings for your client
API Gateway makes this much more straightforward. After I went through Create API, I was able to create an Authorizer that connected with my Cognito User Pool (the clientWeb one). Then, after creating endpoint Resources, I associated them with the authorizer in the Method Request section of their configuration.
I could then send the identity token I get from Amplify:
(await Auth.currentSession()).idToken.jwtToken
as an HTTP header value to the endpoints I configured.

If using multiple UserPool's "App clients", do I need to add them all to IdentityPool's "Authentication providers"?

I'm writing a web app which is using AWS Cognito UserPools for user authentication and IdentityPools for granting direct access to an S3 bucket.
This JavaScript web app has its own App client ID in the UserPool with which it interacts with it.
I also have a couple of Lambda functions doing some admin functions towards the UserPool and IdentityPool. These lambda functions have their own App client ID.
I used to have only a single Authentication provider added to the IdentityPool, with the same App Client ID that the lambda functions have set.
In this setup, the web app was having issues. I was able to authenticate towards the UserPool, but when the identity token was sent to the IdentityPool, I received an error "Token is not from a supported provider of this identity pool.". I believe this was because the aud parameter of the JWT was set to the UserPool ID which was not added to the IdentityPool
I eventually realized that I could get rid of the error if I added another "Authentication provider" to the IdentityPool, filling in the same UserPool ID and the other App client ID.
My question now is - is this the correct approach? Am I perhaps misunderstanding the App client ID meaning and usage? Am I way off base with my approach?
Yes that sounds like a perfectly good approach. If you don't encounter any security or functional issues it is the "correct" approach.