I want to patch the user_metadata of a user in my Auth0 Authentication in react native but I get the following error:
{"error": "Unauthorized", "message": "Missing authentication", "statusCode": 401}
So I am importing Auth0 in my react native:
import Auth0 from "react-native-auth0";
const auth0 = new Auth0({
domain: Config.AUTH0_DOMAIN,
clientId: Config.AUTH0_CLIENT_ID
});
I use the constants Config.AUTH0_DOMAIN and Config.AUTH0_CLIENT_ID from my dashboard from my application.
As a next step I execute the following code:
login = () => {
auth0.webAuth
.authorize({
scope: Config.AUTHO_SCOPE,
audience: Config.AUTH0_AUDIENCE,
device: DeviceInfo.getUniqueID(),
prompt: "login"
})
.then(res => {
auth0.auth
.userInfo({token: res.accessToken})
.then(data => {
fetch(`https://<MY_AUTH_DOMAIN>/api/v2/users/${encodeURIComponent(data.sub)}`, {
method: "PATCH",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"metadata": {first_name: 'John', last_name: 'Doe', skillLevel: 'PRO!'}
})
}).then(res => res.json())
.then(async (data) => {
try {
console.log('user stored', data);
} catch (e) {
console.log("error while user storing", e)
}
})
})
})
}
Whereby Config.AUTHO_SCOPE and Config.AUTH0_AUDIENCE is also from my auth0's app dashboard.
Am I missing some authentication in my headers or is the Management API the wrong choice? Do I need to to this query probably from my Back-End?
Resources:
Official API Doc from the Management API: https://auth0.com/docs/api/management/v2?_ga=2.147997749.368915485.1617866251-2089752765.1617460658#!/Users/patch_users_by_id
Official react-native-auth0 doc: https://auth0.github.io/react-native-auth0/src_management_users.js.html
Thanks for the help!
I was having this issue and I got it working after a little work.
First, I had to configure my project to give metadata write permission in Auth0's dashboard at Applications/Apis.
The two I added were read:current_user and update:current_user_metadata.
Then, in my authorize request, I modified both scope and audience.
audience: 'https://<MY APP DOMAIN>/api/v2/'
scope: 'read:current_user update:current_user_metadata openid profile offline_access'
Next, I got the userId by passing my authentication token to auth.userInfo like so.
auth0.auth.userInfo({token: authToken}).then((response)=>{
return response.sub;
})
Finally, I used the value returned from response.sub along with the authToken that I had setup with special audience and scope to patch the user, and it worked successfully. UserId is what response.sub returned.
auth0.users(authToken).patchUser({id: userId, metadata: newUserMetadata});
EDIT:
One other issue I see with your code snippet, if you want to use fetch, is you didn't put a bearer authorization token in the header. Your fetch response will probably return with a 401 error if that's the case. The code should look something like this:
const serverResponse = await fetch('https://<MYAPP>.auth0.com/api/v2/users/' + user.sub,{
headers:{
Authorization: 'Bearer ' + accessToken
}
})
Related
I am trying to implement Paypal webhooks and everything is working fine except the webhook signature verification. I have read a dozen of posts here on stackoverflow and I still can not figure out what my mistake is, because no matter what I do it always returns { verification_status: "FAILURE" }.
For example here Paypal webhook verification fails everytime one of the posts suggests that this is because the payments are in Sandbox mode. I tried a real actual payment with Live keys, Live environment and so on, it still failed.
https://developer.paypal.com/docs/api/webhooks/v1/#verify-webhook-signature_post this is the endpoint that I am trying to use, and here is what I am doing:
When paypal sends the request to my webhook route, first I am generating the auth token:
const params = new URLSearchParams()
params.append('grant_type', 'client_credentials')
const getAuthToken = await axios.post(
'https://api-m.sandbox.paypal.com/v1/oauth2/token',
params,
{
headers: { 'content-type': 'application/x-www-form-urlencoded' },
auth: {
username: 'usernametoken',
password: 'passwordtoken',
},
},
)
Then I use the token along with the headers received from the initial Paypal request to try to verify the webhook:
const verifyWebhook = await axios.post('https://api-m.sandbox.paypal.com/v1/notifications/verify-webhook-signature', {
auth_algo: req.headers['paypal-auth-algo'],
cert_url: req.headers['paypal-cert-url'],
transmission_id: req.headers['paypal-transmission-id'],
transmission_sig: req.headers['paypal-transmission-sig'],
transmission_time: req.headers['paypal-transmission-time'],
webhook_id: 'webhookID as generated in the developer portal',
webhook_event: req.body.resource,
}, {
headers: {
Authorization: `Bearer ${getAuthToken.data.access_token}`,
},
})
console.log(verifyWebhook.data); // this is always { verification_status: "FAILURE" } even with a REAL transaction
I've been working on a React/Spring project with the ambition of better understanding spring security and while going fairly successful thus far I've found a shortage of information relating to the handling of CSRF tokens between React and Spring boot. As such, I'm at an impasse.
My question is: How do you add and authenticate a CSRF token between React and Spring Boot on POST requests?
So far I've managed to get the CSRF token into my Cookies (thanks spring) and from there, I've attempted accessing the CSRF token and adding it to my HTTP headers although still receiving 403 responses on POST requests.
My spring security config class contains the declaration enabling CSRF outside of http(withHttpOnlyFalse() ).
How I'm trying to access the CSRF token:
I found this online previously for accessing the cookie:
function getCookie(name) {
if (!document.cookie) {
return null;
}
const xsrfCookies = document.cookie.split(';')
.map(c => c.trim())
.filter(c => c.startsWith(name + '='));
if (xsrfCookies.length === 0) {
return null;
}
return decodeURIComponent(xsrfCookies[0].split('=')[1]);
}
How I'm declaring HTTP headers:
let csrfToken = getCookie("XSRF-TOKEN");
console.log("testing csrf token: " + csrfToken);
const res = await fetch(`/register`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": csrfToken,
},
body: JSON.stringify({
firstName: firstName,
lastName: lastName,
mobileNumber: mobileNumber,
email: email,
password: password,
}),
});
Any help/support is greatly appreciated.
I've managed to resolve this.
Considering the difficulty I had sourcing information here's my solution:
Install the react-cookies library (npm install react-cookies)
Inside of the component which triggers the POST request, declare the following:
const cookies = useCookies(['XSRF-TOKEN']);
Pass 'cookies' to your function which facilitates the fetch request - For me this was simply called 'signUp' and was called inside my handleSubmit() method.
const handleSubmit = (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
signUp(data.get("firstName"), data.get("mobileNumber"), data.get("email"),
data.get("password"), setUser, cookies['XSRF-TOKEN'] );
}
My fetch request inside of signUp() looks like the following:
await fetch(`/register`, {
headers: {
"X-XSRF-TOKEN": token,
"Content-Type": 'application/json'
},
credentials: 'include',
method: "POST",
body: JSON.stringify(customerData),
});
I'm sure this isn't the cleanest, nor the most practical way to do this and I hope someone is willing to shed further clarity if this is the case.
This was posted on the basis that I struggled to find a solution and hope this may be of some use/help going forwards.
I am trying to use DialogFlow v2 endpoint but for some reason I am getting not authorized message, eventhou I am able to generate access token using the following command:
Initially I am running this to authorize the service for my local machine to be able to authorize to the service: gcloud auth activate-service-account --key-file=<service-account-key-file.json> then I get access token by following command: gcloud auth print-access-token and this access token I am attaching on the following code:
fetch(configs.baseUrl + "query?v=20150910", {
body: JSON.stringify({query: text, lang: "en", sessionId: "somerandomthing"}),
headers: {
'content-type': 'application/json',
"Authorization": "Bearer " + accessToken,
},
method: 'POST',
})
.then(response => response.json())
.then(data => {
console.log(data.result.fulfillment.speech);
return data.result.fulfillment.speech;
})
.catch(error => console.error(error))
I dont know if this is the right way to achieve a communication with DialogFlow V2?
Please if you could let me know what I am doing wrong and why I it says I am not authorised since I am authorizing by the above commands and been able to get access token!
Edit:
After few changes my code finally looks like this:
fetch("https://dialogflow.googleapis.com/v2beta1/projects/xxx/agent/sessions/xxx/:detectIntent", {
body: JSON.stringify({queryInput: "Hello"}),
headers: {
'content-type': 'application/json',
"Authorization": "Bearer xxxx",
},
method: 'POST',
})
.then(response => response.json())
.then(data => {
console.log(data.result.fulfillment.speech);
return data.result.fulfillment.speech;
})
.catch(error => console.error(error))
and the new error message I get is:
{
"error": {
"code": 400,
"message": "Invalid value at 'query_input' (type.googleapis.com/google.cloud.dialogflow.v2beta1.QueryInput), \"Hello\"",
"status": "INVALID_ARGUMENT",
"details": [
{
"#type": "type.googleapis.com/google.rpc.BadRequest",
"fieldViolations": [
{
"field": "query_input",
"description": "Invalid value at 'query_input' (type.googleapis.com/google.cloud.dialogflow.v2beta1.QueryInput), \"Saanko yhteystiedot?\""
}
]
}
]
}
}
You don't show the baseUrl you're using, but that looks like the V1 API rather than the V2 API. You should migrate your code to V2.
Keep in mind, also, that the access token expires, so you will need to generate a new one periodically. You cannot request a "long lived" token (this is considered insecure), but should have your code call gcloud auth print-access-token (or use a library to do the same thing) before the previous one expires.
Update based on your code once you've moved it to V2:
The queryInput parameter doesn't take a string directly. It must be set to a QueryInput object. This is an enum, so can only have one of the fields specified set. It looks like you want the text field which requires a TextInput object.
So your body parameter might be setup something like this:
var body = {
queryInput: {
text: {
text: "Hello",
language: "en-US"
}
}
};
var bodyStr = JSON.stringify(body);
and then set in your request() options.
Because you have put wrong URL in your project.
Open below image and see which URL use for posturl in your project
https://i.stack.imgur.com/3ym9n.png
I have created react app using the npm module 'create-react-app'
I wanted to use external API for say api.example.com but was unable to call the external API because axios is requesting localhost rather than external API.
I tried the following Code:
class Example extends Component{
static defaultProps={
'url':"api.example.com"
}
handleChange(event){
axios.get(this.props.url+event.target.value)
.then(result=> console.log(result.data)
}
}
}
How to allow react app to access external API?
For example, POST request for added some Product in database:
In example I use JWT authentification for access at API.
JSON.stringify not necessary use, because Axios already implement this feature, here it is used for greater understanding. Don't use this on production!
const jwtToken = 'd70414362252a41ceger5re435gdgd45hjk';
const data = JSON.stringify({
id: '5',
title: 'product'
price: '15000',
description: 'string',
});
const configAxios = {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer + ${jwtToken}`,
},
};
axios.post('https://api.somesite.com/products', data, configAxios)
.then((res) => {
this.date.description = res.data;
console.log(res);
})
.catch((err) => {
console.warn('error during http call', err);
});
It's also important to note that we strictly write the JWT token in the code, although it must be received periodically, this is not realized in this example.
I am new to ReactJS and I am trying to build this app that need to use mailchimp so the user can subscribe for newsletter. I need to make a request using axios? can someone guide me through this? where do i put my api key? Did I do it correct in the bellow code? i put my mailchimps username in 'username' and my apikey in 'xxxxxxxxxxxxxxxxxxx-us16', however, i got the 401 error saying Unauthorized, BUT my console did say Fetch Complete: POST and caught no error.
import React, {Component} from 'react';
import './Subscribe.css';
class Subscribe extends Component {
sub = () => {
let authenticationString = btoa('username:xxxxxxxxxxxxxxxxxxx-us16');
authenticationString = "Basic " + authenticationString;
fetch('https://us16.api.mailchimp.com/3.0/lists/xxxxxxxxx/members', {
mode: 'no-cors',
method: 'POST',
headers: {
'Authorization': authenticationString,
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
email_address: "somedude#gmail.com",
status: "subscribed",
})
}).then(function(e){
console.log('complete')
}).catch(function(e){
console.log("fetch error");
})
};
render () {
return(
<div>
<button onClick={this.sub}> subscribe </button>
</div>
);
};
};
In the documentation, the curl example uses the --user flag. Using this to convert curl commands to an equivalent js code, you need the 'auth' property on the option object of the fetch to make it work.
fetch('https://us16.api.mailchimp.com/3.0/lists/xxxxxxxxx/members', {
method: 'POST',
headers: {
'content-type': 'application/json'
},
body: JSON.stringify({
email_address: "somedude#gmail.com",
status: "subscribed",
},
auth: {
'user': 'username',
'pass': 'xxxxxxxxxxxxxxxxxxx-us16'
})
})
It took me a while to get the syntax right for this. This is an example of a working request using nodejs in a server-side-rendered reactjs app using axios.
It appears "get" requests won't work for this method because of the 401 error: MailChimp does not support client-side implementation of our API using CORS requests due to the potential security risk of exposing account API keys.
However, patch, put, and post seem to work fine.
Example (using async / await)
// Mailchimp List ID
let mcListId = "xxxxxxxx";
// My Mailchimp API Key
let API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxx-us12";
// Mailchimp identifies users by the md5 has of the lowercase of their email address (for updates / put / patch)
let mailchimpEmailId = md5(values["unsubscribe-email-address"].toLowerCase());
var postData = {
email_address: "somedude#gmail.com",
status: "subscribed"
};
// Configure headers
let axiosConfig = {
headers: {
'authorization': "Basic " + Buffer.from('randomstring:' + API_KEY).toString('base64'),
'Accept': 'application/json',
'Content-Type': 'application/json'
}
};
try {
let mcResponse = await axios.post('https://us12.api.mailchimp.com/3.0/lists/' + mcListId + '/members', postData, axiosConfig)
console.log("Mailchimp List Response: ", mcResponse);
} catch(err) {
console.log("Mailchimp Error: ", err);
console.log("Mailchimp Error: ", err["response"]["data"]);
}
You can using the method described there: AJAX Mailchimp signup form integration
You will need to use JSONP otherwise you will get a CORS error.
If you use a modern environment (I mean not jQuery), you can achieve this method using a library like qs or queryString to transform your form data to an uri.
Your final url could look something like:
jsonp(`YOURMAILCHIMP.us10.list-manage.com/subscribe/post-json?u=YOURMAILCHIMPU&${queryString.stringify(formData)}`, { param: 'c' }, (err, data) => {
console.log(err);
console.log(data);
});
It's a bit hacky and I guess Mailchimp can remove this from one day to the other as it's not documented, so if you can avoid it, you'd better do.