I am an experienced JavaScript programmer, but new to PouchDB, Cloudant, and oAuth. When I try to sync PouchDB and Cloudant using Bearer Authorization, I get the error:
"_reader access is required for this request", status: 401
I am trying to write a demo web app, using PouchDB and Cloudant. I set up an IBM account. I created one service called Cloudant-xx. I chose Authentication Method: IBM Cloud IAM (I did not choose "and legacy..."). I went to the dashboard for this service and 1) created a database (myDatabase), and 2) selected the head-profile on the left of the screen, then [CORS], and disabled CORS (for development).
I went back to the service, selected [Service Credentials], and created a new service credential. This gave me an object with {"apikey": "ELB4lEVA...IO", ..., "username": "451c...74-bluemix"}.
I used curl to get an access token:
curl -k -X POST \
--header "Content-Type: application/x-www-form-urlencoded" \
--header "Accept: application/json" \
--data-urlencode "grant_type=urn:ibm:params:oauth:grant-type:apikey" \
--data-urlencode "apikey=ELB4lEVA...IO" \
"https://iam.cloud.ibm.com/identity/token"
which returned {"access_token":"eyJra...6fJns","token_type":"Bearer","expires_in":3600,"expiration":1558965151,"scope":"ibm openid"}
Within the hour, I copied and pasted the access token into my javascript code, ran the code, and got the error "_reader access is required for this request" (see above). I cannot find where to set _reader access. Can anybody help me? Thanks!
let localDb;
const localName = "myDatabase";
const remoteUrl = "https://451...d974-bluemix.cloudantnosqldb.appdomain.cloud/myDatabase";
const token = "eyJra...6fJns";
const syncOptions = {
live: true,
retry: true,
continuous: true,
ajax: {
headers: {
Authorization: "Bearer " + token,
},
},
};
localDb = new PouchDB(localName);
localDb.sync(remoteUrl, syncOptions).on('change', function (info) {
console.log(8888, "change", info);
}).on('paused', function (info) {
console.log(8888, "paused", info);
}).on('active', function (info) {
console.log(8888, "active", info);
}).on('denied', function (err) {
console.log(8888, "denied", err);
}).on('complete', function (info) {
console.log(8888, "denied", info);
}).on('error', function (err) {
console.log(8888, "error", err);
});
console.log(4444, localDb);
In the console I see:
4444 PouchDB {__opts: {…}, auto_compaction: undefined, prefix: "_pouch_", name: "myDatabase", _adapter: "idb", …}
index.js:194
451...d974-bluemix.cloudantnosqldb.appdomain.cloud/:1 GET https://451...d974-bluemix.cloudantnosqldb.appdomain.cloud/myDatabase/ 401
index.js:192
8888 "error" CustomPouchError {error: "unauthorized", reason: "_reader access is required for this request", status: 401, name: "unauthorized", message: "_reader access is required for this request", …}
I answered my own question. Turns out I was following out-of-date examples. In PouchDB 7.0, {ajax: {headers: {}} has been replaced with fetch: function (url, opts) {}. Plus I had to use a PouchDB instance instead of a string for the remote database.
https://pouchdb.com/api.html#create_database
Options for remote databases:
fetch(url, opts): Intercept or override the HTTP request, you can add or modify any headers or options relating to the http request then return a new fetch Promise.
This now works.
let localDb;
const localName = "myDatabase";
const remoteUrl = "https://451...74-bluemix.cloudantnosqldb.appdomain.cloud/myDatabase";
const token = "eyJ...448";
const remoteOptions = {
fetch: function (url, opts) {
opts.headers.set("Authorization", "Bearer " + token);
return PouchDB.fetch(url, opts);
}
};
const syncOptions = {
live: true,
retry: true,
continuous: true,
};
localDb = new PouchDB(localName);
const remoteDb = new PouchDB(remoteUrl, remoteOptions);
localDb.sync(remoteDb, syncOptions).on("change", function (info) {
console.log(8888, "change", info);
}).on("paused", function (info) {...})...
Related
My react native code:
const signin =
(dispatch) =>
async ({ username, password }) => {
try {
console.log(username, password);
const response = await tracker.post(
"/login",
(data = { username, password }),
(headers = {
"content-type": "application/x-www-form-urlencoded",
})
);
await AsyncStorage.setItem("token", response.data.token);
dispatch({ type: "signin", payload: response.data.token });
console.log(response.data.token);
} catch (err) {
console.log(err);
dispatch({
type: "error",
payload: "This is an error, start debugging",
});
}
};
Curl request to FastAPI backend:
curl -X 'POST' \ 'https://fastest.herokuapp.com/login/' \ -H 'accept: application/json' \ -H 'Content-Type: application/x-www-form-urlencoded' \ -d 'grant_type=&username={email}&password={password}&scope=&client_id=&client_secret=
whenever I try to create a new user or sign in with an existing user I keep getting following error:
[AxiosError: Request failed with status code 422]
Is there a better way to send a POST request with curl to signup or login using axios?
Now, I know this is a well documented error on internet, but, somehow, I am unable to find the error and debug it. Any feedback as to what I am doing wrong?
Edit:
FastAPI endpoint code:
#router.post("/",response_model=schemas.Token)
def getLogin(user_Credentials:OAuth2PasswordRequestForm=Depends(),db: Session=Depends(database.get_db)):
user = db.query(models.User).filter(models.User.email == user_Credentials.username).first()
if not user:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"wrong credentials")
if not utils.verify(user_Credentials.password,user.password):
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"wrong credentials")
access_token = oauth2.create_access_token(data={"user_id": user.id})
return {"access_token":access_token, "token_type":"bearer"}
For full code:
Backend FastAPI: here
Frontend react native: here
Error Changed
After adding qs.stringify() according to https://axios-http.com/docs/urlencoded and updating the code as follows:
const signin =
(dispatch) =>
async ({ username, password }) => {
try {
console.log(username, password);
const response = await tracker({
method: "post",
url: "/login",
data: qs.stringify({
username: username,
password: password,
}),
headers: {
"content-type": "application/x-www-form-urlencoded;charset=utf-8",
},
});
console.log(response.data.token);
await AsyncStorage.setItem("token", response.data.token);
dispatch({ type: "signin", payload: response.data.token });
} catch (err) {
console.log(err);
dispatch({
type: "error",
payload: "Start debuggin",
});
}
};
the problem arises now is that token is undefined, but the when I enter same credentials on /docs I get the token.
Final update: got the endpoint wrong for token access
As per Javascript documentation:
A variable that has not been assigned a value is of type undefined.
A method or statement also returns undefined if the variable that is
being evaluated does not have an assigned value. A function returns
undefined if a value was not returned.
In your case, you attempt to retrieve an attribute, namely token, from the JSON repsonse returned by your FastAPI backend. However, such an attribute does not exist in that JSON object. Your API endpoint returns "access_token": access_token, hence, you should instead use response.data.access_token.
Also, for future reference, a response having status code 422 (unprocessable entity) will have a response body that specifies the error message, telling exactly which part of your request is missing or doesn’t match the expected format. This will guide you to fix the error in your code.
Please try to send your authentication data as FormData.
let bodyFormData = new FormData();
bodyFormData.append("username", "value");
bodyFormData.append("password", "value");
then send it as you did:
const response = await tracker.post(
"/login",
(data = bodyFormData),
(headers = {
"content-type": "application/x-www-form-urlencoded",
})
);
It should be mentioned that I didn't do much with react-native, but I guess this work for your case.
I am Trying to execute a GET API request from protractor for which I have to Use the bearer token generated from another POST response . I am able to run the POST request successfully ,but unable to use the generated token in GET request in headers . Below is the code-snippet which I tried , Can anyone provide the proper syntax on this approach .
Note : URL and credentials are masked as they are confidential
var Request = require("request");
describe('post user request', () => {
it('create user test', (done) => {
//1. create user (POST)
Request.post({
// method: 'POST',
"url": "http://example.com",
"body" : {
"username": "abc",
"password": "abc1",
}
}).then((res)=>{
console.log(JSON.stringify(res))
}).then((res) =>{
const token1 = res.token
//2. get user (GET)
Request.get({
// method: 'GET',
"url": "http://example.com`[enter code here][1]`/xyz",
"headers": {
"Authorization" : "Bearer " + token1
}
}).then((res)=>{
console.log(res)
done();
})
})
})
})
Error message :
F
post user request
× create user test
- Failed: Argument error, options.body.
Failures:
1) post user request create user test
Message:
Failed: Argument error, options.body.
Stack:
Error: Argument error, options.body.
at setContentLength (D:\Protractor\node_modules\request\request.js:437:28)
at Request.init (D:\Protractor\node_modules\request\request.js:442:5)
at new Request (D:\Protractor\node_modules\request\request.js:127:8)
at request (D:\Protractor\node_modules\request\index.js:53:10)
at Function.post (D:\Protractor\node_modules\request\index.js:61:12)
at UserContext.<anonymous> (D:\Protractor\Specs_Map\APIfile.spec.js:8:21)
at D:\Protractor\node_modules\jasminewd2\index.j
}).then((res)=>{ console.log(JSON.stringify(res)) this is where your error comes from.
Here you log the result, but don't return it, so the following then won't get any value.
Try the following:
}).then((res)=>{ console.log(JSON.stringify(res)); return res;
Hi All,
I got a scenario in which i am supposed to call a REST api that is secured by a AZURE ACTIVE DIRECTORY. Most of the code runs fine and i am able to get the token using myMSALObj.acquireTokenSilent function too.
401 ERROR COMES WHEN I SEND AJAX CALL USING THAT TOKEN, YOU CAN SEE FOLLOWING CODE
User is there in Active Directory for which i get proper token, i dont know why my ajax call fails when i send that token to rest-api, please help
<script type="text/javascript">
const msalConfig = {
auth: {
clientId: "94edf294-08ae-489f-8621-c6d98009afa8",
authority: "https://login.microsoftonline.com/c483b3c4-21a6-4c93-95ea-7436cf318a68",
redirectUri: "https://localhost:44334/",
},
cache: {
cacheLocation: "sessionStorage", // This configures where your cache will be stored
storeAuthStateInCookie: false, // Set this to "true" if you are having issues on IE11 or Edge
}
};
const myMSALObj = new Msal.UserAgentApplication(msalConfig);
function CallApi() {
// Add scopes for the id token to be used at Microsoft identity platform endpoints.
const loginRequest = {
scopes: ["User.Read"],
};
myMSALObj.loginPopup(loginRequest)
.then((loginResponse) => {
const accessTokenRequest = {
scopes: ["api://8c2b0253-f9e8-442c-bccf-b4a8bbe73b59/access_as_user"]
};
myMSALObj.acquireTokenSilent(accessTokenRequest).then((accessTokenResponse) => {
var accessToken = accessTokenResponse.accessToken;
var apiEndpoint = "https://localhost:44387/api/hello";
var bearer = "Bearer " + accessToken;
console.log("accessToken = ", accessToken);
$.ajax({
url: apiEndpoint,
type: "GET",
beforeSend: function (xhr) { xhr.setRequestHeader("Authorization", bearer) }
}).done(function (response) {
alert("SUCCESS");
console.log("response = ", JSON.stringify(response));
}).fail(function (err) {
console.error("Error Occurred");
console.log("error = ", JSON.stringify(err));
});
})
}).catch(function (error) {
console.log(error);
});
}
</script>
Screenshot of a NEW API Code
Screenshot of JWT.ms (Access Token)
New Screenshot of JWT Token
You should not set the client ID in the appsettings.json file to the client id of your api app. It should be the client id of your client app. According to the jwt analysis diagram you provided, I think it should be: 94edf294- 08ae-489f-8621-c6xxxxxxx.
My bad, Following call was missing in my startup.cs file
app.UseAuthentication();
thanks for your help guys
Specially - #Carl Zhao, #Purushothaman #Rass Masood
I am at my wits end! I am trying to create a customer via the stripe api. Using their example with curl i have no problems.
Here is their example:
curl https://api.stripe.com/v1/customers \
-u sk_test_apikey: \
-d description="Customer for zoey.brown#example.com" \
-d source=tok_visa
It is when i try to do this with axios that i get an error "invalid_request_error" because it isn't properly parsing my data. Here's what i've got:
export const registerNewUser = async (firstName, lastName, email, password) => {
let config = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Bearer ${stripeTestApiKey}`
}
}
let data = {
email: `${email}`,
description: `Customer account for ${email}`
}
await axios.post(stripeCustomerUri, data, config)
.then(res => {
console.log("DEBUG-axios.post--res: ", res)
})
.catch(err => {
console.log(JSON.stringify(err, null, 2))
})
}
and in my console i see that stripe isn't receiving my data in the correct manner. Here's the (useful part of my) response json:
"response": {
"data": {
"error": {
"type": "invalid_request_error",
"message": "Received unknown parameter: {\"email\":\"joe#blow.com\",\"description\":\"Customer account for joe#blow.com\"}", "param": "{\"email\":\"joe#blow.com\",\"description\":\"Customer account for joe#blow.com\"}" } },
Judging by all of my other attempts and this example error, I am not passing my data in the correct format... However, when i pass -d to my curl command everything works as expected... If I send an empty string as data it works as well...
does anyone have an idea why / how this is? How is the "data" object via curl differ from my javascript data object?
The problem was that axios uses application/json content type by default and the stripe api requires form-url-encoded... this requires parsing the data object with a library like querystring before passing through to the stripe api... hope this helps someone!
I was just trying out async/await with request-promise and ran into this error:
RequestError: Error: no auth mechanism defined
at new RequestError (node_modules/request-promise-core/lib/errors.js:14:15)
at Request.plumbing.callback (node_modules/request-promise-core/lib/plumbing.js:87:29)
at Request.RP$callback [as _callback] (node_modules/request-promise-core/lib/plumbing.js:46:31)
at self.callback (node_modules/request/request.js:188:22)
at Auth.onRequest (node_modules/request/lib/auth.js:133:18)
at Request.auth (node_modules/request/request.js:1360:14)
at Context.<anonymous> (test/routes.js:37:41)
From previous event:
at Request.plumbing.init (node_modules/request-promise-core/lib/plumbing.js:36:28)
at Request.RP$initInterceptor [as init] (node_modules/request-promise-core/configure/request2.js:41:27)
at new Request (node_modules/request/request.js:130:8)
at request (node_modules/request/index.js:54:10)
at Context.<anonymous> (test/routes.js:37:24)
It is an API endpoint that I built recently that's supposed to create a new user in MongoDB. It uses Basic Auth provided by Passport strategy, and I've tested with Postman that it works. I'm not exactly sure why this error is being thrown.
My request code (using Mocha):
it("creates a new user", async () => {
const options = {
method: "POST",
uri: `http://localhost:${process.env.PORT}/api/users`,
headers: {
"User-Agent": "Request-Promise",
"Content-Type": "application/json"
},
body: {
email: "test#domain.com",
password: "password",
firstName: "John",
lastName: "Smith"
},
json: true
};
const resp = await request(options).auth(APP_ID, SIGNATURE, false);
expect(resp).to.be.an("object");
});
Edit: I should probably also add that I'm using node 8.2.1 and npm 5.3.0.
Solved for me by changing from:
auth: { Bearer: token }
to:
auth: { bearer: token }
Note the case difference on 'bearer'.
This is usually caused by not providing suitable credentials. The code raising the error can be found here. Have you verified that APP_ID and SIGNATURE are not undefined in your test?
This solution works for me. I have needed to put the token inside the headers :
var rp = require('request-promise');
var uri = 'uri_for_my_post_request';
var token = 'access_token';
var body = {
title: 'My Title',
content : 'My content'
};
var sendPost = async(my_uri,my_token,my_body)=>{
var options = {
method: 'POST',
headers:{
Authorization: ' Bearer ' + my_token
},
uri: my_uri,
body: my_body,
json: true
};
const response = await rp(options);
console.log(response);
}
sendPost(uri,token,body);