No HTTP resource was found that matches the request URI hen revoking grants - tapkey

I have written a function to revoke grants issued for a boundlock as shown in the code snipped below:
For context, I first run a query to get all grants, and then use the ip
UserID to get the specific grant that I want to revoke:
async revokeGrant (user) {
const token = await this.getAuthorizationCodeToken(this.refreshToken)
try {
const { data: allGrants } = await axios.get(
`${this.baseUrl}/owners/${this.operatorAccountId}/grants`,
{
headers: {
'Authorization': `Bearer ${token}`
}
}
)
const targetGrant = allGrants.find(grant => grant.contact.ipUserId === user.userId)
// revoke grant after getting it from above
const revokeResponse = await axios.post(
`${this.baseUrl}/owners/${this.operatorAccountId}/grants/${targetGrant.id}/revoke`,
{
dryRun: true
},
{
headers: {
'Authorization': `Bearer ${token}`
}
}
)
console.log('revokeResponse:', revokeResponse)
} catch (error) {
throw errors.customError(
error.response.data,
platform.responseCodes.InternalServer,
'Device Error',
false
)
}
}
I however keep running into an error:
Message: "No HTTP resource was found that matches the request URI 'https://tapkey-prod-main-rs.azurewebsites.net/api/v1/owners/*********/grants/*********/revoke'."
}
},
isAxiosError: true,
toJSON: [Function]
}

For revoking a grant the dryRun query parameter has to be added:
https://tapkey-prod-main-rs.azurewebsites.net/api/v1/owners/*********/grants/*********/revoke?dryRun=false
For more details please have a look at
https://developers.tapkey.io/openapi/tapkey_management_api_v1/#/Grants/Grants_RevokeById
Info:
The dryRun parameter is required. If omitted, the request will fail.
Please don't use tapkey-prod-main-rs.azurewebsites.net as baseUri as this is not a public hostname and might removed or changed without any notice.

Related

AWS Lambda Function Permission Denied when trying to access AppSync GraphQL endpoint

new to AWS and just not sure how to define the relevant authenitcation to get my lambda function to be able to call my graphQL endpoint for a post req. Assuming I need to put an API key somewhere in this function but just am a bit lost. Any help at all would be great. Have put the function below - created it using the amplify cli and the generategraphqlpermissions flag is set to true if thats any help narrowing it down.
import crypto from '#aws-crypto/sha256-js';
import { defaultProvider } from '#aws-sdk/credential-provider-node';
import { SignatureV4 } from '#aws-sdk/signature-v4';
import { HttpRequest } from '#aws-sdk/protocol-http';
import { default as fetch, Request } from 'node-fetch';
const GRAPHQL_ENDPOINT = <myEndpoint>;
const AWS_REGION = process.env.AWS_REGION || 'us-east-1';
const { Sha256 } = crypto;
const query = /* GraphQL */ `mutation CreateCalendarEvent($input: CreateCalendarEventInput!, $condition: ModelCalendarEventConditionInput) {
createCalendarEvent(input: $input, condition: $condition) {
__typename
id
start
end
title
actions
allDay
resizable
draggable
colour
createdAt
updatedAt
}
}`;
/**
* #type {import('#types/aws-lambda').APIGatewayProxyHandler}
*/
export const handler = async (event) => {
console.log(`EVENT: ${JSON.stringify(event)}`);
console.log(GRAPHQL_ENDPOINT);
const endpoint = new URL(GRAPHQL_ENDPOINT);
const signer = new SignatureV4({
credentials: defaultProvider(),
region: AWS_REGION,
service: 'appsync',
sha256: Sha256
});
const requestToBeSigned = new HttpRequest({
method: 'POST',
headers: {
'Content-Type': 'application/json',
host: endpoint.host
},
hostname: endpoint.host,
body: JSON.stringify({ query }),
path: endpoint.pathname
});
const signed = await signer.sign(requestToBeSigned);
const request = new Request(endpoint, signed);
let statusCode = 200;
let body;
let response;
try {
response = await fetch(request);
body = await response.json();
if (body.errors) statusCode = 400;
} catch (error) {
statusCode = 500;
body = {
errors: [
{
message: error.message
}
]
};
}
return {
statusCode,
// Uncomment below to enable CORS requests
// headers: {
// "Access-Control-Allow-Origin": "*",
// "Access-Control-Allow-Headers": "*"
// },
body: JSON.stringify(body)
};
};
WHen invoking an AWS Service from Lambda, you do not need the keys. Instead, you can give the IAM role that the Lambda function runs under the permissions to invoke that service. In your case, give the role permission to invoke app sync.
More information can be found here:
https://docs.aws.amazon.com/lambda/latest/dg/lambda-permissions.html

Twitter_api_v2 reply to a tweet example

Could anyone Show me an example of your finished Parameters and Endpoint for a Twitter Reply maybe with a Screenshot? Because i dont understand exactly what to type in my Params and, do I got to change anything in the Pre-request Script?
Kind regards Alex
For the Params for https://api.twitter.com/2/tweets I tried:
Key : in_reply_to
Value : tweet_id
And the Result was "errors"
"message": "The query Parameters [in_reply_to] is not one of [expantions,tweet.fields,media.fields,poll.fields,place.fields,user.fields]"
"title":"Invalid Request"
"detail": "One or more Parameters to your request Was invalid.",
"type":"https://api.twitter.com/2/problems/invalid-request"
From the twitter's documentation
query parameter ids is required. You missed that parameter.
I will get tweet this demo
https://twitter.com/pascal_bornet/status/1604754709000200193
BY Postman
Full code by node.js
#1 Get an access token by API Key and API secret
#2 Get text by access token
Credential in config.json
{
"API_KEY" : "7hK your API Key GND",
"API_KEY_SECRET" : "Zr4 your API Key secret 0qX0"
}
Save as get-tweet.js
const axios = require('axios')
const config = require('./config.json');
const getAccessToken = async () => {
try {
const resp = await axios.post(
'https://api.twitter.com/oauth2/token',
'',
{
params: {
'grant_type': 'client_credentials'
},
auth: {
username: config.API_KEY,
password: config.API_KEY_SECRET
}
}
);
// console.log(resp.data);
return Promise.resolve(resp.data.access_token);
} catch (err) {
// Handle Error Here
console.error(err);
return Promise.reject(err);
}
};
const getTweetText = async (token, tweet_id) => {
try {
const resp = await axios.get(
`https://api.twitter.com/2/tweets?ids=${tweet_id}`,
{
headers: {
'Authorization': 'Bearer '+ token,
}
}
);
return Promise.resolve(resp.data);
} catch (err) {
// Handle Error Here
console.error(err);
return Promise.reject(err);
}
};
getAccessToken()
.then((token) => {
console.log(token);
getTweetText(token, '1604754709000200193')
.then((result) => {
console.log(result.data[0].text);
})
})
Get Result
$ node get-tweet.js
AAAAAksadf--very long access token in here ----JlIMJIIse
Is this the future of Christmas shopping?
Credit: Nike
#innovation #AR # VR #AugmentedReality https://~~~

Expecting to get "non_field_errors: Unable to log in with provided credentials", but not getting it

Expectation: when wrong login credentials are provided, "non_field_errors: Unable to log in with provided credentials" is returned, such as below (screenshot from a tutorial which I'm following verbatim)
Reality: instead I'm getting the error below.
This gets printed to the console:
POST http://127.0.0.1:8000/api/v1/token/login 400 (Bad Request)
Interestingly I get this same error when I try to create users with passwords that are too short. I'm not having any issues with axios or the server when I provide the right credentials for log in, or use passwords of sufficient length when creating new users. When trying to catch errors such as these that I'm failing to get the expected result.
My code for catching the error is the same as in the tutorial:
methods: {
submitForm() {
axios.defaults.headers.common['Authorization'] = ''
localStorage.removeItem('token')
const formData = {
username: this.username,
password: this.password
}
axios
.post('/api/v1/token/login', formData)
.then(response => {
const token = response.data.auth_token
this.$store.commit('setToken', token)
axios.defaults.headers.common['Authorization'] = 'Token ' + token
localStorage.setItem('token', token)
this.$router.push('/dashboard/my-account')
})
.catch(error => {
if (error.response) {
for (const property in error.response) {
this.errors.push(`${property}: ${error.response.data[property]}`)
}
} else if (error.message) {
this.errors.push('Something went wrong. Please try again!')
}
})
}
}
Is there something in the server settings that I should change?
I'm using Django, rest framework, and djoser.
Don't know if you're using a custom exception handler in Django rest framework but it looks like the issue could be from the way you're handling the error in your frontend application.
You can handle the errors like this.
methods: {
submitForm() {
axios.defaults.headers.common['Authorization'] = ''
localStorage.removeItem('token')
const formData = {
username: this.username,
password: this.password
}
axios
.post('/api/v1/token/login', formData)
.then(response => {
const token = response.data.auth_token
this.$store.commit('setToken', token)
axios.defaults.headers.common['Authorization'] = 'Token ' + token
localStorage.setItem('token', token)
this.$router.push('/dashboard/my-account')
})
.catch(error => {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
console.log(error.request);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
})
}
Can be found here

error: "unsupported_grant_type" from django oauth2 server

Not sure why django won't accept my POST request for an access token. All my parameters are correct and I already have the authorization code, but a follow-up POST request for the access token gives me this error.
Content-type is correct from what I read from others. If the pkce side was non-accurate it would give me a more specific error about that.
HttpErrorResponse is
{ error: "unsupported_grant_type" } 400 bad request
requestToken(code: string, state: string) {
const clientState = sessionStorage.getItem('pkce-state');
if (clientState !== state) {
console.error('States do not match!');
}
const verifier = sessionStorage.getItem('pkce-verifier');
const params = new URLSearchParams({
grant_type: 'authorization_code',
redirect_uri: 'http://localhost:4200/dashboard',
client_id: 'client_id',
code,
state,
verifier
});
return this.http.post('http://localhost:8000/o/token/',
{
params
},
{
withCredentials: true,
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded'
}
)
});
}
Also tried this:
requestToken(code: string, state: string) {
const clientState = sessionStorage.getItem('pkce-state');
if (clientState !== state) {
console.error('States do not match!');
}
const verifier = sessionStorage.getItem('pkce-verifier');
return this.http.post('http://localhost:8000/o/token/',
{
grant_type: 'authorization_code',
redirect_uri: 'http://localhost:4200/dashboard',
client_id: 'client_id',
code,
state,
verifier
},
{
withCredentials: true,
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
}
)
});
}
Try matching step 7 of my write up precisely:
Use code_verifier
Get rid of the state parameter, which is not needed on a direct https message to the token endpoint
Error messages are often misleading but this will make your message 100% standard and hopefully will work.
Then again, always possible that Django doesn't support this flow properly ...

Manually sign AppSync URL to use in Lambda gives bad signature error

In a Lambda, I would like to sign my AppSync endpoint with aws-signature-v4 in order to use it for a mutation.
The URL generated seems to be ok but it gives me the following error when I try it:
{
"errors" : [ {
"errorType" : "InvalidSignatureException",
"message" : "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details. etc...
} ]
}
Here is my lambda function
import { Context, Callback } from 'aws-lambda';
import { GraphQLClient } from 'graphql-request';
const v4 = require('aws-signature-v4');
export async function handle(event: any, context: Context, callback: Callback) {
context.callbackWaitsForEmptyEventLoop = false;
const url = v4.createPresignedURL(
'POST',
'xxxxxxxxxxxxxxxxx.appsync-api.eu-west-1.amazonaws.com',
'/graphql',
'appsync',
'UNSIGNED-PAYLOAD',
{
key: 'yyyyyyyyyyyyyyyyyyyy',
secret: 'zzzzzzzzzzzzzzzzzzzzz',
region: 'eu-west-1'
}
);
const mutation = `{
FAKEviewProduct(title: "Inception") {
productId
}
}`;
const client = new GraphQLClient(url, {
headers: {
'Content-Type': 'application/graphql',
action: 'GetDataSource',
version: '2017-07-25'
}
});
try {
await client.request(mutation, { productId: 'jfsjfksldjfsdkjfsl' });
} catch (err) {
console.log(err);
callback(Error());
}
callback(null, {});
}
I got my key and secret by creating a new user and Allowing him appsync:GraphQL action.
What am I doing wrong?
This is how I trigger an AppSync mutation using by making a simple HTTP-request, using axios.
const AWS = require('aws-sdk');
const axios = require('axios');
exports.handler = async (event) => {
let result.data = await updateDb(event);
return result.data;
};
function updateDb({ owner, thingName, key }){
let req = new AWS.HttpRequest('https://xxxxxxxxxxx.appsync-api.eu-central-1.amazonaws.com/graphql', 'eu-central-1');
req.method = 'POST';
req.headers.host = 'xxxxxxxxxxx.appsync-api.eu-central-1.amazonaws.com';
req.headers['Content-Type'] = 'multipart/form-data';
req.body = JSON.stringify({
"query":"mutation ($input: UpdateUsersCamsInput!) { updateUsersCams(input: $input){ latestImage uid name } }",
"variables": {
"input": {
"uid": owner,
"name": thingName,
"latestImage": key
}
}
});
let signer = new AWS.Signers.V4(req, 'appsync', true);
signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate());
return axios({
method: 'post',
url: 'https://xxxxxxxxxxx.appsync-api.eu-central-1.amazonaws.com/graphql',
data: req.body,
headers: req.headers
});
}
Make sure to give the IAM-role your Lambda function is running as, permissions for appsync:GraphQL.
Adding an answer here because I had difficulty getting the accepted answer to work and I found an issue on the AWS SDK GitHub issues that said it's not recommended to use the AWS.Signers.V4 object in production. This is how I got it to work using the popular aws4 npm module that is recommended later on in the issue linked above.
const axios = require('axios');
const aws4 = require('aws4');
const query = `
query Query {
todos {
id,
title
}
}`
const sigOptions = {
method: 'POST',
host: 'xxxxxxxxxx.appsync-api.eu-west.amazonaws.com',
region: 'eu-west-1',
path: 'graphql',
body: JSON.stringify({
query
}),
service: 'appsync'
};
const creds = {
// AWS access tokens
}
axios({
url: 'https://xxxxxxxxxx.appsync-api.eu-west/graphql',
method: 'post',
headers: aws4.sign(sigOptions, creds).headers,
data: {
query
}
}).then(res => res.data))
You don't need to construct a pre-signed URL to call an AWS AppSync endpoint. Set the authentication mode on the AppSync endpoint to AWS_IAM, grant permissions to your Lambda execution role, and then follow the steps in the "Building a JavaScript Client" tutorial to invoke a mutation or query.