I have very strange behavior with some users on my web app using Instagram API.
The problem is that I authenticate them and save their token, and all works fine. I can make requests to get media, comments, in other words I can do all. Except one thing, with some users when I try to access v1/users/self I get in response:
Instagram::BadRequest: GET
https://api.instagram.com/v1/users/self.json?access_token=xxx&client_id=xxx&sig=xxx:
400: 'self' keyword requires an authenticated user
And again it is only on this endpoint because I can get information from other endpoint without any problem..
Do you have any suggestions on what I can do?
My Instagram ruby gem configuration:
Instagram.configure do |config|
config.client_id = ENV['INSTAGRAM_client_id']
config.client_secret = ENV['INSTAGRAM_secret']
config.sign_requests = true
end
Related
I am trying to access the Youtube API via python so that I can insert videos into a playlist. To do so I have to use oauth2 to authorize myself. I have looked up many guides and videos and followed their instructions step by step but I always get the same result, saying Error 400: redirect_uri_mismatch
The code that I am using is
from google_auth_oauthlib.flow import InstalledAppFlow
flow = InstalledAppFlow.from_client_secrets_file("client_secrets.json", scopes=['https://www.googleapis.com/auth/youtube.force-ssl'])
flow.run_local_server(port=8080, prompt='consent')
credentials = flow.credentials
print(credentials.to_json())
I have also tried
from google_auth_oauthlib.flow import InstalledAppFlow
flow = InstalledAppFlow.from_client_secrets_file("client_secrets.json", scopes=['https://www.googleapis.com/auth/youtube.force-ssl'])
flow.run_console()
credentials = flow.credentials
print(credentials.to_json())
I understand that this occurs when there is a mismatch between the redirect_uri on the request side and what is listed in the console. But I have triple checked that on https://console.developers.google.com/ I have the redirect URI to be http://localhost.com:8080 and have checked to make sure that my client_secrets.json file reflects the same. I have set my JavaScript origins to also be http://localhost.com:8080. I have set my oauth clientID to be a web application as I am running this in pycharm. However, whenever I run my code I get the same error saying The redirect URI in the request, http://localhost:8080/, does not match the ones authorized for the OAuth client. To update the authorized redirect URIs, visit: https://console.developers.google.com/apis/credentials/oauthclient/${your_client_id}?project=${your_project_number}
I have looked at the other questions on stackOverflow and have tried the solutions that were suggested but none of them have worked. I have no idea why I cannot get authorization and desperately need help
I found out that editing a full_description of a DockerHub repository can be done via a JavaScript API, and figured this would be a fun excuse to learn the requests package for python. The JavaScript API definitely works, e.g. using this simple docker image.
The JS API basically does
Send a POST request to https://hub.docker.com/v2/users/login with the username and password. The server responds with a token.
Send a PATCH request to the specific https://hub.docker.com/v2/repositories/{user or org}/{repo}, making sure the header has Authorization: JWT {token}, and in this case with content body of {"full_description":"...value..."}.
What is troubling is that the PATCH request on the python side gets a 200 response back from the server (if you intentionally set a bad auth token, you get denied as expected). But it's response actually contains the current information (not the patched info).
The only "discoveries" I've made:
If you add the debug logging stuff, there's a 301. But this is the same URL for the javascript side, so it doesn't matter?
send: b'{"full_description": "TEST"}'
reply: 'HTTP/1.1 301 MOVED PERMANENTLY\r\n'
The token received by doing a POST in requests is the same as if I GET to auth.docker.io as decribed in Getting a Bearer Token section here. Notably, I didn't specify a password (just did curl -X GET ...). This is not true. They are different, I don't know how I thought they were the same.
This second one makes me feel like I'm missing a step. Like I need to decode the token or something? I don't know what else to make of this, especially the 200 response from the PATCH despite no changes.
The code:
import json
from textwrap import indent
import requests
if __name__ == "__main__":
username = "<< SET THIS VALUE >>"
password = "<< SET THIS VALUE >>"
repo = "<< SET THIS VALUE >>"
base_url = "https://hub.docker.com/v2"
login_url = f"{base_url}/users/login"
repo_url = f"{base_url}/repositories/{username}/{repo}"
# NOTE: if I use a `with requests.Session()`, then I'll get
# CSRF Failed: CSRF token missing or incorrect
# Because I think that csrftoken is only valid for login page (?)
# Get login token and create authorization header
print("==> Logging into DockerHub")
tok_req = requests.post(login_url, json={"username": username, "password": password})
token = tok_req.json()["token"]
headers = {"Authorization": f"JWT {token}"}
print(f"==> Sending PATCH request to {repo_url}")
payload = {"full_description": "TEST"}
patch_req = requests.patch(repo_url, headers=headers, json=payload)
print(f" Response (status code: {patch_req.status_code}):")
print(indent(json.dumps(patch_req.json(), indent=2), " "))
Additional information related to your CSRF problem when using requests.Session():
It seems that Docker Hub is not recognizing csrftoken named header/cookie (default name of the coming cookie), when making requests in this case.
Instead, when using header X-CSRFToken on the following requests, CSRF is identified as valid.
Maybe reason is cookie-to-header token pattern.
Once updating session header with cookie of login response
s.headers.update({"X-CSRFToken": s.cookies.get("csrftoken")})
There is no need to set JWT token manually anymore for further requests - token works as cookie already.
Sorry, no enough privileges to just comment, but I think this is relevant enough.
As it turns out the JWT {token} auth was valid the entire time. Apparently, you need a / at the end of the URL. Without it, nothing happens. LOL!
# ----------------------------------------------------V
repo_url = f"{base_url}/repositories/{username}/{repo}/"
As expected, the PATCH then responds with the updated description, not the old description. WOOOOT!
Important note: this is working for me as of January 15th 2020, but in my quest I came across this dockerhub issue that seems to indicate that if you have 2FA enabled on your account, you can no longer edit the description using a PATCH request. I don't have 2FA on my account, so I can (apparently). It's unclear what the future of that will be.
Related note: the JWT token has remained the same the entire time, so for any web novices like myself, don't share those ;)
I have been at this for sometime now and wanted to see if anyone had and idea of what I could be doing wrong. What I am trying to do is add a song to a playlist using the provided Spotify Web APIs. According to the documentation on this https://developer.spotify.com/documentation/web-api/reference/playlists/add-tracks-to-playlist/ I need to establish the scope of the user.
"adding tracks to the current user’s private playlist (including collaborative playlists) requires the playlist-modify-private scope" I have created the playlist as collaborative and I am using the login credentials of my personal account to reach this playlist I created. all this is under the same login.
What I am finding is that my scope is not getting added to my token on my call for my token causes a 403 error when I try to add the song.
Here is what that call looks like
https://accounts.spotify.com/authorize/?client_id=mynumber&response_type=code&scope=playlist-modify-private&redirect_uri=http:%2F%2Flocalhost:55141/Home/GetToken/
here are the docs on using authorization to get the correct token.
https://accounts.spotify.com/authorize/?client_id=894400c20b884591a05a8f2432cca4f0&response_type=code&scope=playlist-modify-private&redirect_uri=http:%2F%2Flocalhost:55141/Home/GetToken/
further more if I go into the dev support here
https://developer.spotify.com/documentation/web-api/reference/playlists/add-tracks-to-playlist/
and click the green try button and then request a new token it works.
Bottom line some how my request is not taking my scope request. Any Ideas?
Thanks
To get the token with a specific scope you need to go to the authorize endpoint and get the code. The code is what you want to get to be able http post to the endpoint https://accounts.spotify.com/api/token and get a token with your desired scopes. You can simply get the code by pasting a url like this in your browser...
https://accounts.spotify.com/authorize?client_id=<client_id>&response_type=code&scope=streaming%20user-read-email%20user-read-private&redirect_uri=<redirect_uri>
Only add %20 in between scopes if you have multiple ones
You will then be sent to spotify's website and they'll verify you want to do this. Once you verify it your browser will redirect you to what you set the redirect_uri to be in the url above. At the end of the url that you are sent to, you should be able to see the parameter name code with the code value assigned to it. You then get that code and put it in your http post body params to the https://accounts.spotify.com/api/token endpoint. Make sure you accurately follow the query params requirements in your post method.
An example of the post in python using the requests library:
authorization = requests.post(
"https://accounts.spotify.com/api/token",
auth=(client_id, client_secret),
data={
"grant_type": "authorization_code",
"code": <code>,
"redirect_uri": <redirect_uri>
},
)
authorization_JSON = authorization.json()
return authorization_JSON["access_token"]
In the end you should get a json that shows the scopes you set a long with a refresh the token later on to make more requests.
I know this answer is quite late but I was experiencing the same issue as well which is how I came across this question. I hope this helps anyone that sees this at a later date.
Source: https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow
I want to implement the Google Drive API to my web application using NodeJS and I'm struggling when I try to get a token via OAuth.
I've copied the code from this guide and run the script using Node and it returns an error in this line:
var redirectUrl = credentials.installed.redirect_uris[0];
Googling around I found that I can set that variable as http://localhost:8080 and set the same value in the Authorized redirect URIs configuration in the Google Developers Console and that error goes away, fine, it works. Now it asks for a code that I should get by using an URL.
https://accounts.google.com/o/oauth2/auth?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&response_type=code&client_id=CLIENT_ID&redirect_uri=http%3A%2F%2Flocalhost%3A8080
Then I've added the client id and enter to that URL with Chrome and then returns a connection refused error. No clue what to do in here, I searched about my problem and I can't found an answer. By looking at the direction bar in Chrome I see that there's a parameter called code and after it, there's random numbers and letters. Like this:
http://localhost:8080/?code=#/r6ntY87F8DAfhsdfadf78F7D765lJu_Vk-5qhc#
If I add any of these values it returns this error...
Error while trying to retrieve access token { [Error: invalid_request] code: 400 }
Any ideas on what should I do? Thanks.
Did you follow all the directions on the page you indicated, including all of those in Step 1 where you create the credentials in the console and download the JSON for it? There are a few things to note about creating those credentials and the JSON that you get from it:
The steps they give are a little different from what I went through. They're essentially correct, but the "Go to credentials" didn't put me on the page that has the "OAuth Consent Screen" and "Credentials" tabs on the top. I had to click on the "Credentials" left navigation for the project first.
Similarly, on the "Credentials" page, my button was labeled "Create Credentials", not "Add Credentials". But it was a blue button on the top of the page either way.
It is very important that you select "OAuth Client ID" and then Application Type of "Other". This will let you create an OAuth token that runs through an application and not through a server.
Take a look at the client_secret.json file it tells you to download. In there, you should see an entry that looks something like "redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"] which is the JSON entry that the line you reported having problems with was looking for.
That "urn:ietf:wg:oauth:2.0:oob" is a magic string that says that you're not going to redirect anywhere as part of the auth stage in your browser, but instead you're going to get back a code on the page that you will enter into the application.
I suspect that the "connection refused" error you're talking about is that you used "http://localhost:8080/" for that value, so it was trying to redirect your browser to an application running on localhost... and I suspect you didn't have anything running there.
The application will prompt you to enter the code, will convert the code into the tokens it needs, and then save the tokens for future use. See the getNewToken() function in the sample code for where and how it does all this.
You need to use this code to exchange for a token. I'm not sure with nodejs how to go about this but in PHP I would post the details to the token exchange url. In javascript you post array would look similar to this ....
var query = {'code': 'the code sent',
'client_id': 'your client id',
'client_secret': 'your client secret',
'redirect_uri': 'your redirect',
'grant_type': 'code' };
Hope this helps
Change redirect uri from http://localhost:8080 to https://localhost:8080.
For this add SSL certificates to your server.
I recently opened a new Instagram account and registered a new client. The information I received back from Instagram included the client_id and the client_secret.
I will only run the script on my machine, and be the sole user of the project, so I don't need any user to "log in". But for some reason, whenever I try to make any calls to the Instagram-Node API, it returns the following error:
{ [Error: OAuthAccessTokenException: The access_token provided is invalid.]
code: 400,
error_type: 'OAuthAccessTokenException',
error_message: 'The access_token provided is invalid.',
retry: [Function] }
That's weird to me, because I have an identical setup with an older Instagram account and different credentials, that seem to be working just fine. Then again, that was before November, when Instagram changed some of their API policies.
I use the Instagram-Node like so:
ig.use({
client_id: "dxxxxxxxxxxxxxxxxxxxxxxx2",
client_secret: "4b0xaxaxaxaxaxaxaxaxaxaxa53c03100e4"
});
and make my first call like this:
ig.user_media_recent(user.toString(), options,...
I tried handling the authentication by rerouting my request through the redirect_uri as shown in the Instagram-Node documentation, but even then, all of my requests are unsigned, so it's not clear to me what I would do with the access_token any way.
Any help would be much appreciated!
Okay, the problem is a misunderstanding of the limits of the Sandbox Mode, they essentially make it impossible to look up media from users who are not in your sandbox.
The documentation here says:
The first point is important and it means that the API behaves as if
the only users on Instagram were your sandbox users, and the only
media ever posted were the last 20 for each of these users.
I was trying to find media from users who are not in my sandbox, and so I received an error. The reason that my previous credentials weren't affected is because they are still grandfathered into the grace period, June 2016, at which time they will expire as well. Thanks!
I ran into this same issue. If your app is using oauth, you will cause Instagram to spaz out if you pass the client_secret and client_id stuff again. I had to take these out of my code. So I just pass the access_token now.
ig.use({ access_token: token });
ig.user_media_recent(config.userid, { count: 20 }, function(err, medias, pagination, remaining, limit) {
Were my equivalant statements.
EDIT: I forget to mention. This is after a cycle of these for those confused:
api.authorize_user
api.get_authorization_url