I've been playing with the LinkedIn api (OAuth 2) and I've found an example to help test it. I've followed the tutorial to the letter, but for some reason when I provide my full redirect URL (as requested in the code), I get the error: (invalid_request) A required parameter "client_id" is missing. I'm not sure what I'm doing wrong, but if anyone has any idea, I appreciate the feedback.
Upon searching for a solution, I've found another person struggling with this: "client_id" is missing when authenticate with LinkedIn
Here's the code from the example:
Linkedin.py
from requests_oauthlib import OAuth2Session
from requests_oauthlib.compliance_fixes import linkedin_compliance_fix
# Credentials you get from registering a new application
client_id = SECRET
client_secret = SECRET
# OAuth endpoints given in the LinkedIn API documentation
authorization_base_url = 'https://www.linkedin.com/uas/oauth2/authorization'
token_url = 'https://www.linkedin.com/uas/oauth2/accessToken'
linkedin = OAuth2Session(client_id, redirect_uri='http://localhost:8000')
linkedin = linkedin_compliance_fix(linkedin)
# Redirect user to LinkedIn for authorization
authorization_url, state = linkedin.authorization_url(authorization_base_url)
print ('Please go here and authorize,', authorization_url)
# Get the authorization verifier code from the callback url
redirect_response = input('Paste the full redirect URL here:')
# Fetch the access token
linkedin.fetch_token(token_url, client_secret=client_secret,authorization_response=redirect_response)
# Fetch a protected resource, i.e. user profile
r = linkedin.get('https://api.linkedin.com/v1/people/~')
print (r.content)
Link to example: https://requests-oauthlib.readthedocs.io/en/latest/examples/linkedin.html
Additional Note: The tutorial I used didn't have a date on it. I can only assume the links used in the API tutorial are correct and up to date.
This one is a little old but I thought I'd share some additional changes that need to be made to the LinkedIn example from the oauth requests documentation site.
Along with the updated links, it would seem that LinkedIn is expecting the client_id in the body of the request when trading the verifier code for a a token. I'm not exactly sure where or when it gets left behind but after drilling down in oauth-request source code I found that the fetch method has an argument which forces the client_id to be included in the request body (include_client_id) adding it to the fetch method should make the example work.
linkedin.fetch_token(token_url, client_secret=client_secret,
authorization_response=redirect_response,
include_client_id=True)
The issue is with the URLs, I wrote a similar program and it worked perfectly for me:
from requests_oauthlib import OAuth2Session
from requests_oauthlib.compliance_fixes import linkedin_compliance_fix
# Credentials you get from registering a new application
client_id = '<the client id you get from linkedin>'
client_secret = '<the client secret you get from linkedin>'
redirect_url = '<authorized redirect URL from LinkedIn config>'
# OAuth endpoints given in the LinkedIn API documentation (you can check for the latest updates)
authorization_base_url = 'https://www.linkedin.com/oauth/v2/authorization'
token_url = 'https://www.linkedin.com/oauth/v2/accessToken'
# Authorized Redirect URL (from LinkedIn configuration)
linkedin = OAuth2Session(client_id, redirect_uri=redirect_url)
linkedin = linkedin_compliance_fix(linkedin)
# Redirect user to LinkedIn for authorization
authorization_url, state = linkedin.authorization_url(authorization_base_url)
print('Please go here and authorize,', authorization_url)
# Get the authorization verifier code from the callback url
redirect_response = input('Paste the full redirect URL here:')
# Fetch the access token
linkedin.fetch_token(token_url, client_secret=client_secret,
authorization_response=redirect_response)
# Fetch a protected resource, i.e. user profile
r = linkedin.get('https://api.linkedin.com/v1/people/~')
print(r.content)
I hope it helps!
While this may not be the reason for your issue, you are using an older version of LinkedIn's authentication URLs. From LinkedIn's OAuth documentation (https://learn.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow?context=linkedin/consumer/context) your authorziation_base_url should be
https://www.linkedin.com/oauth/v2/authorization
Related
I have followed the guide below to obtain a Google Ads API refresh token for my application.
https://github.com/googleads/googleads-python-lib/wiki/API-access-on-behalf-of-your-clients-(web-flow)
Using the script below, everything worked, but the response only had an access token, while the refresh token was None.
from googleads import oauth2
import google.oauth2.credentials
import google_auth_oauthlib.flow
# Initialize the flow using the client ID and secret downloaded earlier.
# Note: You can use the GetAPIScope helper function to retrieve the
# appropriate scope for AdWords or Ad Manager.
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
'client_secret.json',
[oauth2.GetAPIScope('adwords')])
# Indicate where the API server will redirect the user after the user completes
# the authorization flow. The redirect URI is required.
flow.redirect_uri = 'https://www.example.com'
# Generate URL for request to Google's OAuth 2.0 server.
# Use kwargs to set optional request parameters.
authorization_url, state = flow.authorization_url(
# Enable offline access so that you can refresh an access token without
# re-prompting the user for permission. Recommended for web server apps.
access_type='offline',
# Enable incremental authorization. Recommended as a best practice.
include_granted_scopes='true',
# approval_prompt='force'
)
print("\n" + authorization_url)
print("\nVisit the above URL and grant access. You will be redirected. Get the 'code' from the query params of the redirect URL.")
auth_code = input('\nCode: ').strip()
flow.fetch_token(code=auth_code)
credentials = flow.credentials
print(credentials.__dict__)
The problem seemed to be that I have already completed these steps before.
The solution was to include approval_prompt='force' in flow.authorization_url(). After generating the authorization_url this way, the response included a refresh token as well.
I am creating a Python script to use Microsoft Graph API services using the requests_oauthlib library. I am able to create successfully an OAuth2.0 session, get an authorization URL to open in an internet browser window to authenticate, and then I am redirected to the redirect URL that I previously indicated when I registered my app in the Azure portal (https://portal.azure.com). Then I copy the full redirect URL to paste into my application. At that point, my app reads the URL that I pasted, exchanges the authentication code that is embedded in the URL for an OAuth authentication token that is perfectly valid. To make sure, I check it in https://jwt.ms, and it is perfect except for the scopes granted. These scopes do not match the scopes that I requested in my OAuth session.
SCRIPT CODE
# details from the library can be found at https://pypi.org/project/requests-oauthlib/
from requests_oauthlib import OAuth2Session
client_id = <the client id from the Azure Portal when I registered my app>
client_secret = <the client secret I got from the Azure Portal>
redirect_uri = <the redirect_uri that I specified in the Azure Portal>
authorization_base_url = 'https://login.microsoftonline.com/<my tenant code>/oauth2/v2.0/authorize'
token_url = 'https://login.microsoftonline.com/<my tenant code>/oauth2/v2.0/token'
scopes = ["https://graph.microsoft.com/User.Read", "https://graph.microsoft.com/offline_access"]
# OAuth2.0 Authentication
msgraph = OAuth2Session(client_id, scope = scopes, redirect_uri=redirect_uri) # creates a OAuth 2.0 session object
# Redirect user to microsoft for authorization
# offline for refresh token
# force to always make user click authorize
authorization_url, state = msgraph.authorization_url(authorization_base_url, access_type="offline", prompt="select_account")
print('Please go here and authorize,', authorization_url) # user needs to click on this URL, authenticate and copy the URL that will be given
# Get the authorization verifier code from the callback url
redirect_response = input('Paste the full redirect URL here: ') # the user has to paste the url with the authorizaton code provided after authenticating
print('redirect_response: ', redirect_response)
# Fetches the access token AFTER the authentication code was given in the previous step
token = msgraph.fetch_token(token_url, client_secret=client_secret, authorization_response=redirect_response) # gets the access token
print('token: ', token)
but I get the following warning message:
Warning: Scope has changed from "https://graph.microsoft.com/User.Read https://graph.microsoft.com/offline_access" to "profile https://graph.microsoft.com/User.Read openid email".
API PERMISSIONS IN AZURE PORTAL
Microsoft Graph (2)
Files.ReadWrite.All
offline_access
As you can see in the Azure permissions above, the privileges (scopes) in the Azure portal are exactly the same scopes that I requested, so my question is where did these 'openid' and 'email' scopes come from? I have been able to overcome the warning message, but I can't request the privileges that I need. I even created a brand new application in the Azure portal, but I have the same problem. Is there something wrong with the requests_oauthlib library or I'm doing something wrong?
Thank you
When requesting scopes, you don't need a fully qualified domain name (FQDN) for Graph scopes (they're the default) and you shouldn't use them for non-Graph scopes (openid, profile, email, and offline_access are OpenID/AAD scopes, not Graph).
scopes = ["User.Read", "offline_access"]
I'm trying to use python-linkedin library here https://github.com/ozgur/python-linkedin
to send an invitation to linkedin contact via script
But on following code:
from linkedin import linkedin
API_KEY = 'wFNJekVpDCJtRPFX812pQsJee-gt0zO4X5XmG6wcfSOSlLocxodAXNMbl0_hw3Vl'
API_SECRET = 'daJDa6_8UcnGMw1yuq9TsjoO_PMKukXMo8vEMo7Qv5J-G3SPgrAV0FqFCd0TNjQyG'
RETURN_URL = 'https://localhost:8000'
authentication = linkedin.LinkedInAuthentication(API_KEY, API_SECRET, RETURN_URL) #, linkedin.PERMISSIONS.enums.values())
print authentication.authorization_url # open this url on your browser
application = linkedin.LinkedInApplication(authentication)
I get "The redirect_uri does not match the registered value" when pasting authentication.authorization_url into the browser
Can someone please help ? Feel free to suggest any other methods ;)
Thanks
When you grant access to the application, you will be redirected to the return url with the following query strings appended to your RETURN_URL
Take the key value after http://localhost:8000/?code=
add it after the authentication.authorization_code = "the code provided"
use authentication.get_access_token()
then application = linkedin.LinkedInApplication(token='the token provided')
Quick usage example:
from linkedin import server
application = server.quick_api(KEY, SECRET)
application.get_profile()
For test automation purpose, I would like to use requests and requests-oauthlib library to access an API.
The API use an oauth2 authentication with google account, however it's not a google API. As my test tool should be able to run unattended, I would like to be able to obtain an access token that I could then refresh automatically for an indefinite amount of time.
Something looking like this example from requests-auth documentation would be great. It involves a manual login once, and then I can refresh the token.
https://requests-oauthlib.readthedocs.io/en/latest/examples/google.html
from requests_oauthlib import OAuth2Session
client_id="xxxx.apps.googleusercontent.com"
client_secret="xxxxx"
redirect_uri = 'https://localhost/callback'
authorization_base_url = "https://accounts.google.com/o/oauth2/auth"
token_url ="https://accounts.google.com/o/oauth2/token"
scope = [
"https://www.googleapis.com/auth/userinfo.email",
"https://www.googleapis.com/auth/userinfo.profile",
]
google = OAuth2Session(client_id, scope=scope, redirect_uri=redirect_uri)
# Redirect user to Google for authorization
authorization_url, state = google.authorization_url(authorization_base_url,
access_type="offline", prompt="select_account")
print 'Please go here and authorize,', authorization_url
redirect_response = raw_input('Paste the full redirect URL here:')
# Fetch the access token
google.fetch_token(token_url, client_secret=client_secret,
authorization_response=redirect_response)
r = google.get('https://www.googleapis.com/oauth2/v1/userinfo')
print r.content
However, I need to adapt to my API, and I can't find a way.
I can set authorization_base_url = "https://example.net/.auth/login/google"
and obtain the redirection URL but it doesn't work afterward.
I don't know either what I should set as scope.
Should I get Id and secret from the API provider ?
Or is there other solution ?
I am trying to get started with the Box.com SDK and I have a few questions.
from boxsdk import OAuth2
oauth = OAuth2(
client_id='YOUR_CLIENT_ID',
client_secret='YOUR_CLIENT_SECRET',
store_tokens=your_store_tokens_callback_method,
)
auth_url, csrf_token = oauth.get_authorization_url('http://YOUR_REDIRECT_URL')
def store_tokens(access_token, refresh_token):
# store the tokens at secure storage (e.g. Keychain)
1)What is the redirect URL and how do I use it? Do I need to have a server running to use this?
2)What sort of code to I need in the store_tokens method?
The redirect URL is only required if you're runng a Web application that needs to respond to user's requests to authenticate. If you're programtically authenticating, you can simply set this as http://localhost. In a scenario where you require the user to manually authenticate, the redirect URL should invoke some function in your web app to store and process the authentication code returned. Do you need a server running? Well, if you want to do something with the authentication code returned, the URL you specify should be under your control and invoke code to do something useful.
Here's an example of what the store_tokens function should look like. It should accept two parameters, access_token and refresh_token. In the example below, the function will commit these to a local store for use when the API needs to re-authenticate:
From here:
"""An example of Box authentication with external store"""
import keyring
from boxsdk import OAuth2
from boxsdk import Client
CLIENT_ID = 'specify your Box client_id here'
CLIENT_SECRET = 'specify your Box client_secret here'
def read_tokens():
"""Reads authorisation tokens from keyring"""
# Use keyring to read the tokens
auth_token = keyring.get_password('Box_Auth', 'mybox#box.com')
refresh_token = keyring.get_password('Box_Refresh', 'mybox#box.com')
return auth_token, refresh_token
def store_tokens(access_token, refresh_token):
"""Callback function when Box SDK refreshes tokens"""
# Use keyring to store the tokens
keyring.set_password('Box_Auth', 'mybox#box.com', access_token)
keyring.set_password('Box_Refresh', 'mybox#box.com', refresh_token)
def main():
"""Authentication against Box Example"""
# Retrieve tokens from secure store
access_token, refresh_token = read_tokens()
# Set up authorisation using the tokens we've retrieved
oauth = OAuth2(
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
access_token=access_token,
refresh_token=refresh_token,
store_tokens=store_tokens,
)
# Create the SDK client
client = Client(oauth)
# Get current user details and display
current_user = client.user(user_id='me').get()
print('Box User:', current_user.name)
if __name__ == '__main__':
main()
I suggest taking a look at the OAuth 2 tutorial. It will help give a better understanding of how OAuth works and what the various parameters are used for.
The redirect URL is set in your Box application's settings:
This is the URL where Box will send an auth code that can be used to obtain an access token. For example, if your redirect URL is set to https://myhost.com, then your server will receive a request with a URL that looks something like https://myhost.com?code=123456abcdef.
Note that your redirect URI doesn't need to be a real server. For example, apps that use a WebView will sometimes enter a fake redirect URL and then extract the auth code directly from the URL in the WebView.
The store_tokens callback is optional, but it can be used to save the access and refresh tokens in case your application needs to shutdown. It will be invoked every time the access token and refresh token changes, giving you an opportunity to save them somewhere (to disk, a DB, etc.).
You can then pass in these tokens to your OAuth2 constructor at a later time so that your users don't need to login again.
If you're just testing, you can also pass in a developer token. This tutorial explains how.
This is the most basic example that worked for me:
from boxsdk import Client, OAuth2
CLIENT_ID = ''
CLIENT_SECRET = ''
ACCESS_TOKEN = '' # this is the developer token
oauth2 = OAuth2(CLIENT_ID, CLIENT_SECRET, access_token=ACCESS_TOKEN)
client = Client(oauth2)
my = client.user(user_id='me').get()
print(my.name)
print(my.login)
print(my.avatar_url)