Having trouble using newly generated token making API calls. PARTNER_AUTHENTICATION_FAILED? - python

I am currently able to generate a token from Docusign's API.
I am using the python wrapper docusign-esign.
{
'access_token': <JWT token>,
'data': None,
'expires_in': '3600',
'refresh_token': None,
'scope': None,
'token_type': 'Bearer'
}
For Developers: API and Integration Key Information
Using
Implicit Grant
RSA Keypairs
redirect URI set
status LIVE
BASE_URL='https://demo.docusign.net/restapi'
OAUTH_BASE_URL='account-d.docusign.com'
I was using the envelope API to get envelope status with auth header as
'Authorization Bearer <JWT token>'
I get the following 400 error:
{
"errorCode": "PARTNER_AUTHENTICATION_FAILED",
"message": "The specified Integrator Key was not found or is disabled. Invalid account specified for user."
}

The public ID, integrator key, API Account ID and API Username are all separate IDs and are used at a different moment when making API calls. This has caused me a huge amount of frustration when dealing with the API.
To help clarify (this is specific to python's wrapper for Docusign):
when using request_jwt_user_token
it requires
client_id -- integrator key
user_id -- ID you want to impersonate, which can be found in the admin page > users > API Username (which is a UUID)
oauth_host_name -- account-d.docusign.com for dev or account.docusign.com for production
private_key_bytes -- the RSA Keypairs in the file (private key)
scopes -- typically signature impersonate for JWT implicit grant
then when using the EnvelopeAPI.create_envelope it required an account_id, which was not the client_id nor user_id. The account_id for me was the API Account ID for in For Developers: API and Integration Key Information. So either copy and paste the API Account ID from docusign or get it using the JWT grant example here
This was probably totally my fault for not understanding it, but hopefully, this is some info that can help someone else.

do you actually replace with a JWT token? and how did you generate this token?
Please make sure you read and follow the instructions here - https://github.com/docusign/eg-01-python-jwt

Related

Google Analytics API authentication failure using JWT

I want to connect to Google Analytics Reporting API to fetch data, For which I have been provided with details of the service account in JSON format which contains details like (type, project_id, client_email, client_id, private_key,client_x509_cert_url, auth_provider_x509_cert_url)
Using this JSON file I am able to connect and fetch required report data via Python code Reporting API quickstart. However, due to business requirements, I have to establish the connection using HTTP Rest API.
So based on the details of the same service account I am trying to authenticate using JWT by referring to Google Docs Addendum: Service account authorization without OAuth so that once I get the signature I can use that as a static token and make next API call to get report data https://analyticsreporting.googleapis.com/v4/reports:batchGet and passing Request Body
But while testing in https://jwt.io/ & also in https://irrte.ch/jwt-js-decode/index.html signature creation is failing with an Invalid Signature error.
Can someone please help to understand what am I missing here?
Header
{
"alg": "RS256",
"typ": "JWT",
"kid": "<service account's private key ID>"
}
Payload
{
"iss": "<service account's email address i.e. client_email>",
"sub": "<service account's email address i.e. client_email>",
"aud": "https://oauth2.googleapis.com/token",
"iat": <UTC Unix Epoch Start Time>,
"exp": <UTC Unix Epoch End Time>
}
And then pasted X.509 PUBLIC CERTIFICATE generated for the service account and in Private key pasted Private key again which is from JSON file of service account
-----BEGIN CERTIFICATE-----\nMIrrhherhehrgssreheheherhehehehrhrdsfsfzcsvsvsvscssvsrjnfvdsfsscscscshgeferttyyuuuuuuuuuuudDxE/Q\n-----END CERTIFICATE-----\n
-----BEGIN PRIVATE KEY-----\nLDSVSVSCSYUNJKOLPDFSSSFSFSFSSFSFSFSFSFSFSSFSFSFSFSFSFSFSSSSSSSSSGGGGGGGGGGGGGGGGGGGGGGUUUUUUUUUUUUUUUUUM=\n-----END PRIVATE KEY-----\n
PS: I have tried to test with \n without \n as well as with prefixes BEGIN, END and without it still have the same result.

Power BI Rest API Requests Not Authorizing as expected

I have built a python application to access read only Power BI Rest API’s. I am automating the collection of tenant activity. However despite configuring my Azure App and using the service principal to generate an access token, the response I receive from the API request is one of an unauthorised response:
{"error": {"code": "PowerBINotAuthorizedException", "pbi.error": {"code":
"PowerBINotAuthorizedException", "parameters": {}, "details": [], "exceptionCulprit": 1}}}
I have found a number of similar issues posted online, however feel that I have done everything that is suggested but am still not able to get it working. I would appreciate any guidance.
The steps that I have taken are:
Configured an Azure App, adding the Application Permission for Power Bi Service-Tenant.Read.All
Screenshot of App Settings in Azure Portal
Requested my access token based upon the Client Credentials Flow using my app's client_ID and client_Secret as documented in the below link:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
I successfully receive a token using the script below:
import requests
azureTenantID = "xxxxxxxxxxxxxxxxx"
azureClientId = "xxxxxxxxxxxxxxxxx"
azureClientSecret = "xxxxxxxxxxxxxxxxxx"
url = f"https://login.microsoftonline.com/{azureTenantID}/oauth2/v2.0/token"
payload = {
"grant_type": "client_credentials",
"client_id": azureClientId,
"client_secret": azureClientSecret,
"scope": "https://analysis.windows.net/powerbi/api/.default"
}
# Header HAS to be x-www-form-urlencoded for MS to accept it.
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
# Return POST content as JSON.
r = requests.post(url, data=payload, headers=headers).json()
# Grab the access token.
response = r.get("access_token")
# Concatenate with Bearer string
access_token = "Bearer {r['access_token']}"
Configured my Power BI Tenant Settings to enable Service Principals to use API's.
Screenshot of Admin API Setting
Screenshot of Developer API Setting
Note that I added the Service Principal as a member of the Security Group for which both of these settings are enabled
Execute my Get request to the API
The followings script returns a good response when I take an access token from the Power BI REST API Documentation's 'Try it out' feature, but not when I generate the token as above.
import requests
# Initialise parameters.
url = "https://api.powerbi.com/v1.0/myorg/admin/groups?$top=1000&$expand=datasets,dataflows,reports,users,dashboards"
headers = {'Authorization': get_access_token2()}
# Get response.
response = requests.get(url, headers=headers)
response = response.json()
Any assistance would be appreciated !
I just went through this exact scenario that you described, and in the end we had to engage Microsoft support to solve it.
Although extremely counter intuitive, if the app that you create for your service principal authentication has any Power BI permissions assigned to it then the access token that is generated (when passed to Power BI REST Admin API) will return an error response that reports PowerBINotAuthorizedException.
To be even more specific, if the access token that you pass to the Power BI API has a roles key/value pair, then you will get a PowerBINotAuthorizedException.
In your case, the issue is easier because you have listed out what permissions you granted. You mentioned that you Configured an Azure App, adding the Application Permission for Power Bi Service-Tenant.Read.All. In order to resolve this issue, you will need to remove that permission.
For future readers, you can troubleshoot this by decoding your access token using a JWT token decoder like one found at jstoolset.com. If your app has permissions allocated to the scope that you have requested (https://analysis.windows.net/powerbi/api/.default is the typical Power BI scope that you request in your authorization) and you decode your JWT token then you will see a roles key/value pair. The presence of this roles is essentially the issue. It does not matter that the values there might match up to the Required Scope in the Power BI REST Admin API documentation. It was described to us as if there is a roles value in your access token then when the token is presented to the Power BI API the roles that are granted are attempted to be used, which ultimately results in a PowerBINotAuthorizedException because service principals are not allowed to use a certain role.
If you have an app that you have removed all permissions from, but still has a value coming through in your access token for the roles key/value pair, then I would suggest starting with a new app with no permissions allocated to it, and simply add the new app to the existing security group that you originally created. This is how we realized that this truly was the issue, and were then able to reconcile from there.
EDIT: Microsoft has now updated their API documentation on the relevant endpoints to reflect this information. For example, in Admin - Groups GetGroupUsersAsAdmin the Required Scope now reads:
Tenant.Read.All or Tenant.ReadWrite.All
Relevant only when authenticating via a standard delegated admin access token. Must not be present when authentication via a service principal is used.

Google Cloud: sign a JWT while impersonating a service account

Goal:
I have a cloud function that impersonates a service account based on the service account email provided to it. I then want to use the impersonated service account to sign a jwt.
What I tried:
I have set up the impersonation of the service account like this:
credentials = google.auth.impersonated_credentials.Credentials(
source_credentials=SOURCE_CREDENTIALS,
target_principal=SA_EMAIL,
target_scopes=TARGET_SCOPES,
lifetime=300)
This brings me to a sub question: What target scopes do I need to specify?
After creating the impersonated credentials, I try to use signer (docs) to sign the payload of the JWT:
payload = {
'iat': now,
"exp": now + expiry_length,
[...]
}
signer = target_credentials.signer
jwt = google.auth.jwt.encode(signer, payload)
The error message I receive is:
AttributeError: 'Credentials' object has no attribute 'key_id'
Question:
I suspect I am not on the right track with my approach using signer.
How is it possible to achieve my goal?
In your example code, you have only create the payload section. A signed JWT also requires a header.
The header looks like this:
header = {
'kid': pkey_id, # Signing Private Key ID
"alg": "RS256", # Google uses SHA256withRSA
"typ": "JWT"
}
The header and payload are base64 encoded and then concatenated with a dot (period symbol) in between. You sign the combined data.
The problem that you will have is that you need to private key id (pkey_id in my example). That value is located in the service account JSON key file. However, Google does not publish the JSON key file that is used for signing. The key used is private to Google. You can get the private key by signing some data first as the pkey_id is returned as part of the response. Then sign your JWT.
I recommend that you switch from using the Sign Blob API and use the SignJwt API instead. The SignJwt API does not require that you create a JWT header.
IAM Service Account Credentials API
Method: projects.serviceAccounts.signJwt

How to do google Sign In with the help of idToken in Django

This is the code I use to retrieve idToken in my flutter app
Future<void> _handleSignIn() async {
try {
final result = await _googleSignIn.signIn();
final ggAuth = await result!.authentication;
print(ggAuth.idToken); // this is the one that I use as token value
print(ggAuth.accessToken);
} catch (error) {
print(error);
}
}
And this is the code I use to access user info in my backend.
from google.oauth2 import id_token
from google.auth.transport import requests
try:
idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)
userid = idinfo['sub']
print(userid)
except ValueError:
print('Invalid token)
But after replacing the token variable with the token received from flutter app and replacing the CLIENT_ID with the id generated for my app (available in the console) , it still throws the error of invalid token. What am I doing wrong?
EDIT- When I use https://jwt.io/ to decode the token it works as expected and I get all the details.
Authentication Think of the id token as your birth certificate. It just identifies you as a person.
Authorization Think of the access token as your drivers license its what contains the permissions that you have to drive a car.
An Id token does not out write give you permission to access any data on google servers. With an access token you have been authorized to access some data in this case some profile information.
The issue you are having is that you are using sign-in in. Sign in is Open id connect think of it as a birth certificate (Id token). There is a user their who is signing in to your app. They are in fount of their computer. By default with Google signin gives you get basic profile information. What you are doing with Jwt.io is checking the claims that are returned in the Id token. Id tokens are just the token that allows your application to identify that the user is logged in. There should also be a sub claim there you should use this id to map the user to your integral user system. There may be a user name and email address in the claims but you can not guarantee that they will be there every time google has stated they do not always return these claims.
To get user profile information after the user has logged in you should be using the people api the people.get method when passed the access token will return to you the profile information of the currently authenticated user.
beyond that you should IMO not be passing tokens to your backend if you want the token in the backend you should log the user in using your backend language.
Okay so the idToken that I had was correct but flutter terminal was not able to print its full length and because of which I was copying only half the token and was getting a signature error when checking manually.

How to decode Firebase JWT token in Python

I have added Firebase to allow clients to authenticate directly from the web app client (browser). I am using the firebase-web JS package and it works great. I can see in my browser that I receive a user object with information about the user, including an idToken.
I need to then authenticate this user on my server backend, which is python django. In the Firebase docs I found a how-to for exactly what I am trying to do, which is to verify the id token.
Since they don't have the supported Firebase sdk for python, I need to use a third party solution. I have come to the python-jose package after finding it listed on the jwt.io site. The example looks simple enough:
jwt.decode(token, 'secret', algorithms=['RS256'])
This is my first time using JWT. I don't know what to use for the 'secret'. I tried pasting my id token as token, and the web API key from the Firebase console for secret, but got this error:
jose.exceptions.JWKError: RSA key format is not supported
I also tried the JWT debugger, which seems to be reading most of my id token correctly, but the signature verification is looking for a public and/or a private keys, which like the 'secret' are escaping me.
I am really at a loss for how to find this secret, and how to verify the JWT id token in general. The information on the Firebase docs (third-party section) is:
Finally, ensure that the ID token was signed by the private key
corresponding to the token's kid claim. Grab the public key from
https://www.googleapis.com/robot/v1/metadata/x509/securetoken#system.gserviceaccount.com
and use a JWT library to verify the signature. Use the value of
max-age in the Cache-Control header of the response from that endpoint
to know when to refresh the public keys.
I have tried pasting the whole json blob from that googleapis url into the JWT debugger, but still getting an "invalid signature" alert. I don't understand how to use that public key.
Should python-jose work for this approach? If so, what should I use for the secret? If not, can someone point me in the right direction?
Thanks.
I finally found the answer I was looking for in this post: Migrating Python backend from Gitkit to to Firebase-Auth with python-jose for token verification
Since the time of the post there have been updates made to the python-jose package, which gives better support for firebase id tokens. Here is some working code ( jose version 1.3.1 ) on how to use python to decode the firebase id token:
import urllib, json
from jose import jwt
idtoken = "<id token passed to server from firebase auth>"
target_audience = "<firebase app id>"
certificate_url = 'https://www.googleapis.com/robot/v1/metadata/x509/securetoken#system.gserviceaccount.com'
response = urllib.urlopen(certificate_url)
certs = response.read()
certs = json.loads(certs)
#will throw error if not valid
user = jwt.decode(idtoken, certs, algorithms='RS256', audience=target_audience)
print user

Categories

Resources