I'm having trouble figuring out how I could authenticate and authorize a IBM Cloud Function to use the IBM Cloud Foundry API to manage some routes on one of my Cloud Foundry apps.
The Cloud Foundry API says I'll need a valid bearer token, and that I can get a token using the Cloud Foundry UAA server. I don't think using OAuth2 fits for my use case because I am not accessing anyone else's resources on their behalf.
How can I authenticate & authorize my Cloud Function to access the Cloud Foundry API?
EDIT:
I just found Generating an IBM Cloud IAM token by using an API key. Is an IAM token compatible with the Cloud Foundry API? I see in this document that the https response describes the token type as Bearer.
I have created an example in Node.js that is based on the steps from my previous answer to this question.
The first action expects a valid apikey in params.apikey as input parameter and returns a bearer token:
/**
*
* main() will be run when you invoke this action
*
* #param Cloud Functions actions accept a single parameter, which must be a JSON object.
*
* #return The output of this action, which must be a JSON object.
*
*/
function main(params) {
const axios = require('axios');
const querystring = require('querystring');
return axios.post('https://iam.cloud.ibm.com/cloudfoundry/login/us-south/oauth/token',
querystring.stringify({
grant_type: "password",
username: "apikey",
password: params.apikey
}), {
auth: {
username: 'cf'
}
})
.then(res => {
console.log(`statusCode: ${res.status}`);
console.log(res.data);
return {
token: res.data.access_token
};
})
.catch(error => {
console.error(error);
return {
error: err.message
};
})
}
The second action expects a valid bearer token in params.token and is then executing an API call against the IBM Cloud CF Public API. In this example a get request against /v2/organizations:
/**
*
* main() will be run when you invoke this action
*
* #param Cloud Functions actions accept a single parameter, which must be a JSON object.
*
* #return The output of this action, which must be a JSON object.
*
*/
function main(params) {
const axios = require('axios');
axios.defaults.headers.common['Authorization'] = "bearer " + params.token;
const querystring = require('querystring');
return axios.get('https://api.us-south.cf.cloud.ibm.com/v2/organizations')
.then(res => {
console.log(`statusCode: ${res.status}`);
console.log(res.data);
return {
organizations: res.data.resources
};
})
.catch(error => {
console.error(error);
return {
error: error.message
};
})
}
Now you can put both actions into a sequence, so that the output from the first action (the bearer token) is used as token within the second action.
I can't guide you the full way right now, but I hope the information that I can provide will guide you into the right direction.
First you'll need to identify the authorization endpoint:
curl http://api.us-south.cf.cloud.ibm.com/info
With that and a valid IAM API token for your account you can get the bearer token that will work against the IBM Cloud CF Public API:
curl -v -X POST "https://iam.cloud.ibm.com/cloudfoundry/login/us-south/oauth/token" -d "grant_type=password&scope=&username=apikey&password=<yourApiKey>" --user "cf:"
Note that you need to append /oauth/token to the authorization endpoint that you received in step 1.
The response contains the access token that you need. For this example, just put it into an environment variable:
export TOKEN=<yourAccessToken>
Next try a command against the IBM Cloud CF Public API:
curl "https://api.us-south.cf.cloud.ibm.com/v2/organizations" -X GET -H "Authorization: bearer $TOKEN"
I hope once you have followed these steps in your command line, you will be able to do the same steps in your IBM Cloud Function and you'll reach your goal.
Related
I'm following through this link: https://developers.google.com/identity/protocols/oauth2/service-account#httprest_1 in order to have my flutter app log to a log bucket in a google cloud project. Currently getting a
{
"error": "invalid_client",
"error_description": "The OAuth client was not found."
}
when I run the code below to get the access token in dart:
var jsonFile =
await File(jsonPath).readAsString();
var map = jsonDecode(jsonFile);
final jwt = JWT(
{
'iss': map['client_email'],
'sub': map['client_email'],
'aud': map['token_uri'],
'iat': (DateTime.now().millisecondsSinceEpoch / 1000).floor(),
'exp':
(DateTime.now().add(Duration(hours: 1)).millisecondsSinceEpoch / 1000)
.floor(),
},
issuer: map['private_key_id'],
);
final token = jwt.sign(SecretKey(map['private_key']));
print(token);
final accessToken = await http.post(
Uri.parse(map['token_uri']),
headers: {
HttpHeaders.contentTypeHeader: 'application/x-www-form-urlencoded',
},
body: {
'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion': token,
},
);
The JSON file is the credentials of a service account with logging admin role in the GCP project.
Invalid client means that the client id or the client secret that you are using are not valid.
As per the official documentation,
When attempting to get an access or refresh token, you will get an
"Invalid client" error if you provide an incorrect OAuth 2.0 Client
Secret. Make sure the client_secret value you're using in access and
refresh token calls is the one for the OAuth 2.0 Client ID being used,
as found in your GCP Credentials page.
Also refer to this SO link Github link for more information.
Strapi Version: 4.1.5
Operating System: Debian GNU/Linux 9
Database: PostgreSQL 13
Node Version: v14.16.0
NPM Version: 6.14.11
Yarn Version: v1.22.5
Hi everyone, I can’t seem to find consistent information on how to use permissions with a custom plugin in Strapi. I want to make an endpoint available to my front-end (Next.JS) application, but only when the front-end application has authenticated as a user and using the JWT that is returned from authenticating with Strapi. I keep getting a 401 returned.
Here’s what I’m doing:
I used this page to set up authentication in Strapi. I have a user created in Strapi, and from the front-end, I can authenticate and it returns a JWT token. When I set up collection types to only be accessible with the “authenticated” role, I can access those collection types in the api using this JWT token. So all of that works. The problem is that I can’t get this to work with my custom plugin, and I’m not sure why. I still get a 401 error instead.
Here’s how I set up the permissions:
Based on this page, I initially tried to leverage the isAuthenticated permission that the Users & Permissions plugin provides:
{
method: "GET",
path: "/progress",
handler: "memberProgress.getProgress",
config: {
policies: ['plugins::users-permissions.isAuthenticated']
},
},
Unfortunately, this did not work. The server raised an error, saying that this could not be found. So back on the document linked above, I decided to take the approach of creating my own gloabl permission. I created src/policies/is-authenticated.js with the following contents:
module.exports = (policyContext, config, { strapi }) => {
if (policyContext.state.user) { // if a session is open
// go to next policy or reach the controller's action
return true;
}
return false; // If you return nothing, Strapi considers you didn't want to block the request and will let it pass
};
Then, I modified my plugin’s route as follows:
{
method: "GET",
path: "/progress",
handler: "memberProgress.getProgress",
config: {
policies: ['global::is-authenticated']
},
},
This is all based on that document I linked to. Unfortunately, this still does not work. It seems to find the permission (server doesn’t raise an error about it), but when I try to access my plugin’s endpoint with the JWT token, I just get a 401 error.
Here is how I’m trying to access the endpoint on the front-end:
// VERIFIED, auth works and I get the expected jwt
const strapiAuth = await strapiApiAuth();
if ( strapiAuth && strapiAuth.hasOwnProperty("jwt") ) {
try {
const response = await axios.get(
`${process.env.STRAPI_BACKEND_URL}/member-progress/progress?year=2022&name=&pageSize=10&page=1`,
{
headers: {
Accept: "application/json",
Authorization: `Bearer ${strapiAuth.jwt}`
},
timeout: 500,
}
);
console.log(response);
} catch (error) {
// This is where I land with the 401 error
console.log(error);
}
}
Strapi check if you have a valid jwt by default with "authenticated" role, but you must mark the permission to your custom endpoint in "Settings→User & Permission Plugin→Roles" of admin panel also.
I am trying to delete the ArgoCD app from the API, but getting no session information while calling the Delete API.
{"error":"no session information","code":16,"message":"no session information"}
In the swagger, it seems pretty much easy
https://myargocd.example.com/swagger-ui#operation/ApplicationService_Delete
I already set ENV for the token
ARGOCD_TOKEN=my-token
I need to pass the ArgoCD token as a cookies header to the delete API.
For
<=v1.2
Then pass using the HTTP SetCookie header, prefixing with argocd.token:
$ curl $ARGOCD_SERVER/api/v1/applications --cookie "argocd.token=$ARGOCD_TOKEN"
{"metadata":{"selfLink":"/apis/argoproj.io/v1alpha1/namespaces/argocd/applications","resourceVersion":"37755"},"items":...}
v1.3
Then pass using the HTTP Authorization header, prefixing with Bearer:
$ curl $ARGOCD_SERVER/api/v1/applications -H "Authorization: Bearer $ARGOCD_TOKEN"
{"metadata":{"selfLink":"/apis/argoproj.io/v1alpha1/namespaces/argocd/applications","resourceVersion":"37755"},"items":...}
https://argo-cd.readthedocs.io/en/stable/developer-guide/api-docs/#authorization
and finally my function is able to delete apps from the ArgoCD
async function deleteApp(AppName){
let url = 'https://argocd.exampple.com/api/v1/applications/'+AppName
let res = await fetch(url, {
headers: {
Cookie: 'argocd.token=' + process.env.ARGOCD_AUTH_TOKEN
},
method: 'DELETE'
})
let body = await res.json()
return body
}
I am not able to send a POST request to my Hasura endpoint from my Flutter client and even from POSTMAN.
Here is my current error:
{"errors":[{"extensions":{"path":"$","code":"invalid-json"},"message":"Error
in $: not enough input"}]}
I added endpoint my_endpoint/v1/graphql and HASURA_GRAPHQL_ADMIN_SECRET which I set in Heroku dashboard. ( This value now shows up on my deployed herokuapp console)
My client is using ferry-graphql like this
Client initClient(String url, String secret) {
final link = HttpLink(
url,
defaultHeaders: {
'x-hasura-admin-secret': secret,
},
);
final cache = Cache();
final client = Client(
link: link,
cache: cache,
);
return client;
}
I am not sure what else I should add for my client request header to access hasura.
Something like this might help you: https://github.com/gql-dart/ferry/issues/95#issuecomment-848735562
I'm currently developping an API with aws-cdk and I'm testing it locally with aws-sam-cli and docker. I wanted to add the requirement of an API Key to call the API.
Here is the code inside my stack:
const api = new apigw.RestApi(this, "MyAPI", {
restApiName: "My API",
description: "BLABLABLA API",
});
const myLambdaIntegration = new apigw.LambdaIntegration(myLambda, {
proxy: false,
});
// Endpoints of the API
api.root.addResource("test").addMethod("GET", myLambdaIntegration, {
apiKeyRequired: true,
});
Then I build this stack and synth it (npm run build ; cdk synth --no-staging myStack > template.yaml
And try to test it locally
sam local start-api
When I request my api without any API KEY, the API returns me the result of my lambda. 😭
I expected it to return me an error like {"message":"Missing Authentication Token"}
Does anyone have an idea of what is going on?
I suspect it's because authorizations are ignored locally but didn't find anything about that...
Thanks in advance! 😁
Edit: After deploying this stack, the API correctly asks me for a token.