I'm using Laravel 5.1 with Lucadegasperi's OAuth 2. My API Server is on AWS ElasticBeanstalk, with an SSL cert, and is delivered through AWS Cloudfront distribution.
Cloudfront made it easier to get the https cert on there and save money, as to add the cert directly to the EC2, you'd need expensive Load Balancing.
Anyway, I'm getting the following error through DHC when making a request with an OAuth2 access token to my production server, but having no issues on my localhost:
"error": "invalid_request",
"error_description": "The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. Check the \"access token\" parameter."
For prod/local, I first make a request to get the access token (changing the URL accordingly):
POST: http://myapp-api.localhost/1.0/oauth/access_token
HEADERS: Content-Type: application/json
BODY: {
"username" : "my#myemail.com",
"password" : "password",
"client_id" : "myclientid",
"client_secret" : "myclientsecret",
"grant_type" : "password",
"refresh_grant" : "refresh_token"
}
This gets the access token, which I then use to get a quest successfully:
GET: http://myapp-api.localhost/1.0/quests/1
HEADERS: Authorization: Bearer aTNk...
Both getting the access token and requesting an OAuth2 protected route, /quests/1, on localhost work fine.
But on AWS server, making the same request below results in error above:
GET: https://api.myapp.com/1.0/quests/1
HEADERS: Authorization: Bearer zYrA...
Related
CloudFront-> S3 static->API Gateway->lambda
CloudFront has s3-type origin, not as website endpoint. S3 static sends through post request, API Gateway already has CORS specified. I tried to replicate exact same settings in S3 CORS section:
[
{
"Access-Control-Allow-Origin": [
"http://frontend-erjan-vote.s3-website-us-east-1.amazonaws.com",
"http://frontend-erjan-result.s3-website-us-east-1.amazonaws.com"
],
"Access-Control-Allow-Methods": [
"GET",
"HEAD"
],
"Access-Control-Allow-Headers": [
"accept",
"content-type"
]
}
]
but it turns out it needs other params and does not recognize the ones above:
There were 5 validation errors: *
MissingRequiredParameter: Missing required key
'AllowedMethods' in
params.CORSConfiguration.CORSRules[0] *
MissingRequiredParameter: Missing required key
'AllowedOrigins' in params.CORSConfiguration.CORSRules[0] *
UnexpectedParameter: Unexpected key 'Access-Control-
Allow-Origin' found in
params.CORSConfiguration.CORSRules[0] *
UnexpectedParameter: Unexpected key 'Access-Control-Allow-
Methods' found in
params.CORSConfiguration.CORSRules[0] *
UnexpectedParameter: Unexpected key 'Access-Control-Allow-
Headers' found in params.CORSConfiguration.CORSRules[0]
The cloudfront gives "cors response invalid". Usually I solved it by not triggering preflight request at all: I made content-type: "text/plain" and not "application/json". However the error stays in cloudfront: d3u9gxsy6062na.cloudfront.net, its actual s3 works fine without errors:
http://frontend-erjan-result.s3-website-us-east-1.amazonaws.com
from CloudFront it gives this bug and not renders the page properly, but renders fine in s3 bucket!
Ensure CORS response header values are valid
A cross-origin resource sharing (CORS) request was blocked because of invalid or missing response headers of the request or the associated preflight request .
To fix this issue, ensure the response to the CORS request and/or the associated preflight request are not missing headers and use valid header values.
Note that if an opaque response is sufficient, the request's mode can be set to no-cors to fetch the resource with CORS disabled; that way CORS headers are not required but the response content is inaccessible (opaque).
Currently, I have an issue by creating a valid signature v4 presigned url for a PUT request.
The urls are generated on the server side and are then provided to clients.
The clients should use the urls to upload a file over an API Gateway into an Amazon S3 bucket.
To authenticate the request API Gateway IAM authentication is used.
For my use case, a direct upload into an S3 bucket via "s3-presigned-url" is not possible.
The following code describes the generation of the presigned url and is written in Typescript. The generation of the signature v4 url is based on the AWS provided package #aws-sdk/signature-v4.
import { SignatureV4 } from "#aws-sdk/signature-v4";
import { Sha256 } from "#aws-crypto/sha256-js";
import { formatUrl } from "#aws-sdk/util-format-url";
const createSignedUrl = async (credentials: {
accessKeyId: string,
secretAccessKey: string,
sessionToken: string,
}, requestParams: {
method: "GET" | "PUT",
host: string,
protocol: string,
path: string,
}) => {
const sigv4 = new SignatureV4({
service: "execute-api",
region: process.env.AWS_REGION!,
credentials: {
accessKeyId: credentials.accessKeyId,
secretAccessKey: credentials.secretAccessKey,
sessionToken: credentials.sessionToken,
},
sha256: Sha256,
applyChecksum: false
});
const signedUrlRequest = await sigv4.presign({
method: requestParams.method,
hostname: requestParams.host,
path: requestParams.path,
protocol: requestParams.protocol,
headers: {
host: requestParams.host,
},
}, {
expiresIn: EXPIRES_IN,
});
const signedUrl = formatUrl(signedUrlRequest);
return signedUrl
};
I use Postman to test the presinged urls.
If I generate a presigned url for an GET request, everything works fine.
If I generate a presigned url for an PUT request and don't set a body in Postman for the PUT request, everything works fine. But I have an empty file in my bucket ;-(.
If I generate a presigned url for an PUT request and set a body in Postman (via Body -> binary -> [select file]), it fails!
Error message:
The request signature we calculated does not match the signature you provided. ...
The AWS documentation https://docs.aws.amazon.com/general/latest/gr/create-signed-request.html describes that the payload has to be hashed within the canonical request. But I don't have the payload at that time.
Is there also an UNSIGNED-PAYLOAD option if I want to generate an presigned url for a PUT request that is sent to an API Gateway, like described in the documentation for the AWS S3 service?
How do I configure the SignatureV4 object or the presign(...) method call to generate a valid PUT request url with UNSIGNED-PAYLOAD?
I was able to compare my generated canonical requests with the canonical request that is expected by the Amazon API Gateway.
The Amazon API Gateway always expects a hash of the payload no matter if I add the query param X-Amz-Content-Sha256=UNSIGNED-PAYLOAD to the url or not.
Thus the option "UNSIGNED-PAYLOAD" as canonical request hash value for API Gateway IAM Authentication is not possible, as would be possible with Amazon S3 service.
I want to implement the Google Cloud speech to text using a service account. What i have try is i have set the environment variable to that json and send the post request to this url 'https://speech.googleapis.com/v1/speech:longrunningrecognize'.
Code:
req = requests.post(url, data={
"audio":{
"content":enc
},
"config":{
"audioChannelCount":2,
"enableSeparateRecognitionPerChannel":True,
"enableWordTimeOffsets":True,
"diarizationConfig":{
"enableSpeakerDiarization": True,
"minSpeakerCount": 1,
"maxSpeakerCount": 2
},
}})
Error:
403
{
"error": {
"code": 403,
"message": "The request is missing a valid API key.",
"status": "PERMISSION_DENIED"
}
}
The error message indicates that you are not authenticating correctly. The way to do this is to pass an authentication token as a Bearer Token header in your request.
The following documentation explains how to generate the required credentials and pass them with the request, this provides an overview of service accounts Service accounts overview
Creating a service account instructions Creating service accounts
Once you have created the service account you generate the credentials which are stored in json format, these are then passed as a Bearer Token
I have two services (APIs) deployed on GCP Cloud Run. Call them service-one.myDomain.com and service-two.myDomain.com. I would like service-one to be authenticated in calling service-two independently of what any user is doing.
I've read and implemented the instructions from GCP Cloud Run docs on Authenticating service-to-service (https://cloud.google.com/run/docs/authenticating/service-to-service) but service-one.myDomain.com is unsuccessful in calling service-two.myDomain.com receiving a 401:Unauthorized response.
Any thoughts on how to get service-one to successfully call service-two?
Here's my setup:
IAM and service accounts:
On google IAM, I created two service accounts and granted them both the "Cloud Run Invoker" (roles/run.invoker) role:
service-one#myproject.iam.gserviceaccount.com
service-two#myproject.iam.gserviceaccount.com
Inside Cloud Run I changed the service account from the "Default compute service account" to the service accounts I created. I assigned service-one#myproject.iam.gserviceaccount.com for service-one.myDomain.com and service-two#myproject.iam.gserviceaccount.com for service-two.myDomain.com
OIDC Auth token:
In service-one.myDomain.com I make a call to the metadata server to get a token (jwt) from the following url:
http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://service-two.myDomain.com with a request header set as {'Metadata-Flavor': 'Google'} The request is successful and the token I receive is decoded to have the following payload:
{
"alg": "RS256",
"kid": "9cef5340642b157fa8a4f0d874fe7543872d82db",
"typ": "JWT"
}
{
"aud": "https://service-two.mydomain.com",
"azp": "100959068407876085761",
"email": "service-one#myproject.iam.gserviceaccount.com",
"email_verified": true,
"exp": 1572806540,
"iat": 1572802940,
"iss": "https://accounts.google.com",
"sub": "100953168404568085761"
}
Http request:
Using the token I make a request from service-one.myDomain.com to an http endpoint on service-two.myDomain.com. I set the request header with {'Authorization': 'Bearer {token}'} ({token} is value of token).
Http Response:
The response is a 401 Unauthorized and my logs show the response headers to include:
{'WWW-Authenticate': 'Bearer error="invalid_token" error_description="The access token could not be verified"'}
With a content of:
"
<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>401 Unauthorized</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Unauthorized</h1>
<h2>Your client does not have permission to the requested URL <code>/health</code>.</h2>
<h2></h2>
</body></html>
"
I'm stumped.... any ideas on what I'm missing to get service-one to authenticate to service-two?
The answer was to use the gcp cloud run generated Url as the audience in the OIDC token request. And relatedly the "aud" field in the jwt.
My discovery was that Service-to-Service authentication in cloud run does not support custom domains (myDomain.com). I was using my custom domain.
(I feel like a bonehead) thanks #guillaumeblaquiere
Am trying to get access-token from keycloak using postman application. The flow which I am using is Auth Code flow. The Auth URI am giving is
http://localhost:8080/auth/realms/realm_name/openid-connect/token
Even in keycloak I made some changes of valid redirect URI to http://localhost:8080/* in the Security-admin-console under clients but still am receiving a web page stating we are sorry instead of login page when am hitting the get request token button in postman application
can someone help me with this issue
Getting accessToken in Postman:
POST http://localhost:8080/auth/realms/realm-name/protocol/openid-connect/token
Headers:
Content-Type: application/x-www-form-urlencoded
Body x-www-form-urlencoded:
client_id: your-client
username: user-you-are-using
password: password-for-user
grant_type: password
client_secret: 11112222-3333-4444-5555-666666666666 (client secret is required if client "Access Type"="confidential")
Getting refreshToken in Postman:
POST http://localhost:8080/auth/realms/realm-name/protocol/openid-connect/token
Headers:
Content-Type: application/x-www-form-urlencoded
Body x-www-form-urlencoded:
client_id: your-client
grant_type: refresh_token
refresh_token: refresh-token-from-previous-request
client_secret: 11112222-3333-4444-5555-666666666666 (client secret is required if client "Access Type"="confidential")