I have a PowerBI and trying to connect to API. I can get the Token Bearer Authentication, but when I Trying to get the data using Anonymous credentials, the power BI return this message "we couldn't authenticate with the credentials provided POWER BI".
Has anyone ever experienced this?
This is my code,
() => let body = Json.FromValue([user = user, password = password]) , getToken = Json.Document( Web.Contents( urlbase, [ RelativePath = urlauth, Headers=[#"Content-Type"="application/json"], Content=body ] ) ), Source = getToken, dadosAutenticacao = Source[dadosAutenticacao], token = "Bearer " & dadosAutenticacao[tokenAcesso], request = Json.Document( Web.Contents( urlbase, [ RelativePath= urlrequest, Headers=[#"Content-Type"="application/json", Authorization=token] ] ) ) in request The problem occurs when I add this part of the code. request = Json.Document( Web.Contents( urlbase, [ RelativePath= urlrequest, Headers=[#"Content-Type"="application/json", Authorization=token] ] ) ) in request
Related
I am trying to make the Keyclock SSO work with the webapp and Grafana which is embedded in.
I have made the grafana integerate with the keyclock and I am able to login using the keyclock into grafana. But when I embed the grafana as inframe into the webapp, and log into the webapp with keyclock, am shown the error as
login.OAuthLogin(missing saved state)
This is my flask config
{
"web": {
"issuer": "http://localhost:8080/realms/internal",
"auth_uri": "http://localhost:8080/realms/internal/protocol/openid-connect/auth",
"client_id": "flask",
"client_secret": "nlY4o3kIrReiwwsYo0FrKFDHIZvfdXd5",
"redirect_uris": [
"http://localhost:5000/*"
],
"token_uri": "http://localhost:8080/realms/internal/protocol/openid-connect/token",
"token_introspection_uri": "http://localhost:8080/auth/realms/internal/protocol/openid-connect/token/introspect",
"userinfo_uri": "http://localhost:8080/realms/internal/protocol/openid-connect/userinfo"
}
}
Following is my grafana config
[auth.generic_oauth]
enabled = true
name = OAuth
allow_sign_up = true
client_id = grafana
client_secret = CA6OIr8z9v3ZPY4yhPWMSwZWJIPWaRK7
scopes = openid email profile
;email_attribute_name = admin#test.com
;email_attribute_path = admin#test.com
auth_url = http://localhost:8080/realms/internal/protocol/openid-connect/auth
token_url = http://localhost:8080/realms/internal/protocol/openid-connect/token
api_url = http://localhost:8080/realms/internal/protocol/openid-connect/userinfo
;allowed_domains =
;team_ids =
;allowed_organizations =
role_attribute_path = "contains(roles[*], 'Admin') && 'Admin' || contains(roles[*], 'Editor') && 'Editor' || 'Viewer'"
;tls_skip_verify_insecure = false
;tls_client_cert =
;tls_client_key =
;tls_client_ca =
I have the following settings for the cookies and embedding
cookie_samesite = lax
allow_embedding = true
I am getting an 500 Error auth to the grafana is redirected
SameSite=Lax:
Only send the cookie in a first-party context (meaning the URL in the address bar matches the cookie domain). Do not send it with the following cross-origin requests: non-GET, AJAX, iframe, image requests etc. It saves the user from cross-site request forgery.
So Lax is blocking cookie "propagation" to iframe in your use case. None is better option in this case for cookie_samesite Grafana config.
This one has been driving me mad for a couple of days and I can't find a solution. Can someone point me towards one? Thank you in advance!
What I want:
I want to successfully use the authorization_code flow for a Power BI Extension.
What I've done:
I've setup an OAuth2 flow in Power Query M and when I target my localhost IdentityServer, I can login with the user login screen and I get an Access Token that Power BI can use. This works, but it doesn't work on a published IdentityServer (same code, same database). So what am I missing?
Here's what happens:
I have this Power Query M code (it's pretty standard, I found it online and it works on localhost):
StartLogin = (resourceUrl, state, display) =>
let
authorizeUrl = oauthUrl & "connect/authorize?" & Uri.BuildQueryString([
response_type = "code",
client_id = client_id,
redirect_uri = redirect_uri,
state = state,
scope="myscope"
])
in
[
LoginUri = authorizeUrl,
CallbackUri = redirect_uri,
WindowHeight = windowHeight,
WindowWidth = windowWidth,
Context = null
];
FinishLogin = (context, callbackUri, state) =>
let
// parse the full callbackUri, and extract the Query string
parts = Uri.Parts(callbackUri)[Query],
// if the query string contains an "error" field, raise an error
// otherwise call TokenMethod to exchange our code for an access_token
result = if (Record.HasFields(parts, {"error", "error_description"})) then
error Error.Record(parts[error], parts[error_description], parts)
else
TokenMethod("authorization_code", "code", parts[code])
in
result;
TokenMethod = (grantType, tokenField, code) =>
let
queryString = [
grant_type = grantType,
redirect_uri = redirect_uri,
client_id = client_id,
client_secret = client_secret
],
queryWithCode = Record.AddField(queryString, tokenField, code),
tokenResponse = Web.Contents(oauthUrl & "connect/token", [
Content = Text.ToBinary(Uri.BuildQueryString(queryWithCode)),
Headers = [
#"Content-type" = "application/x-www-form-urlencoded",
#"Accept" = "application/json"],
ManualStatusHandling = {400}
]),
body = Json.Document(tokenResponse),
result = if (Record.HasFields(body , {"error", "error_description"})) then
error Error.Record(body[error], body[error_description], body)
else
body
in
result;
What happens is that an IE frame pops up to prompt for my credentials:
The normal login page
Once I login on localhost, I get my AccessToken, life's good :-)
However, once I login on the deployed IdentityServer, I get this one, a 400:
Failing on deployed IdentityServer
The address is: res://ieframe.dll/http_400_webOC.htm#https://identityserverurl/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fresponse_type%3Dcode%26client_id%3DPowerBI%26redirect_uri%3Dhttps%253A%252F%252Foauth.powerbi.com%252Fviews%252Foauthredirect.html%26state%3D852bddfc-638c-44f6-90be-a04346908753%26scope%3Dmyscope
I think the problem has something to do with Internet Explorer and the way the window is being presented, but I can't figure out why it DOES work on localhost, just NOT on a deployed server. The client settings are identical on both localhost and on the deployed IdentityServer (it's on a develop server; they target the same database).
I know on a deployed IdentityServer the home page is not available, so the "https://identityserverurl/" will give a 404. Is something similar going on here?
What am I missing?
Any help is much appreciated! It's the final step to getting it all to work.
Best regards,
Remco
Update: Added IdentityServer logging and Fiddler Trace:
GET /connect/authorize?response_type=code&client_id=PowerBI&redirect_uri=https%3A%2F%2Foauth.powerbi.com%2Fviews%2Foauthredirect.html&state=d2f420fb-a98a-4327-b8f1-ebb8937f8b00&scope=openid%20profile%20offline_access%20myscope HTTP/1.1
GET /Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fresponse_type%3Dcode%26client_id%3DPowerBI%26redirect_uri%3Dhttps%253A%252F%252Foauth.powerbi.com%252Fviews%252Foauthredirect.html%26state%3Dd2f420fb-a98a-4327-b8f1-ebb8937f8b00%26scope%3Dopenid%2520profile%2520offline_access%2520myscope HTTP/1.1
There's not much else going on. It just simply stops when I click login.
I am trying to query my cosmos db for documents and I am having trouble generating the correct authorization header, the example in the official documentation does not show querying.
I am trying it in Postman using Javascript by POST to this URI:
POST https://MyDatabase.documents.azure.com:443/dbs/MyContainer/colls/MyDocuments/docs
With these headers:
The authorization is generated like this:
var now = new Date().toUTCString();
pm.request.headers.upsert({key: "x-ms-date", value: now })
var verb = 'POST';
var resourceType = "docs";
var resourceLink = 'dbs/MyContainer/colls/MyCollection/docs';
var text = (verb || "").toLowerCase() + "\n" +
(resourceType || "").toLowerCase() + "\n" +
(resourceLink || "") + "\n" +
now.toLowerCase() + "\n" +
"" + "\n";
//Hash and Encode by using the masterkey.
var key = CryptoJS.enc.Base64.parse("MyMasterKey");
var signature = CryptoJS.HmacSHA256(text, key).toString(CryptoJS.enc.Base64);
var authToken = encodeURIComponent("type=master&ver=1.0&sig=" + signature);
pm.request.headers.upsert({key: "Authorization", value: authToken })
Here is the error I am getting:
{
"code": "Unauthorized",
"message": "The input authorization token can't serve the request. Please check that the expected payload is built as per the protocol, and check the key being used. Server used the following payload to sign: 'post\ndocs\ndbs/MyContainer/colls/MyCollection\nwed, 27 may 2020 19:34:41 gmt\n\n'\r\nActivityId: 724657c7-0532-4c5d-a7ff-c95900ef13cf, Microsoft.Azure.Documents.Common/2.11.0"
}
I am guessing my signature is created wrong, what is the correct format?
Our docs on our Authorization Header should have what you're looking for.
hope this is helpful.
A required fix for your scenario is that you have to remove "/docs" at the end of the resourceLink value -keep it in the request URL- and also if your containter was created using a partitionKey you have to add the following header:
'x-ms-documentdb-query-enablecrosspartition': true
I'm trying to make a chatbot in Hangouts Chat.
I'm referring this documentation to implement account linking.
Its default version is working but when I try to generate access_token and refresh token using Token Endpoint. It gives
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
Here is my callback function code.
def on_oauth2_callback():
"""Handles the OAuth callback."""
print("IN CALLBACK ", flask.request.args)
oauth2_callback_args = OAuth2CallbackCipher.decrypt(
flask.request.args['state'])
user_name, redirect_url = (
oauth2_callback_args['user_name'],
oauth2_callback_args['redirect_url'])
oauth2_flow = flow.Flow.from_client_secrets_file(
OAUTH2_CLIENT_SECRET_FILE,
scopes=PEOPLE_API_SCOPES,
redirect_uri=flask.url_for('auth.on_oauth2_callback', _external=True),
state=flask.request.args['state'])
oauth2_flow.fetch_token(authorization_response=flask.request.url)
print("REDIRECT URL ", redirect_url)
auth_code = request.args.get('code')
data = {'code': auth_code,
'client_id': "xxxxxxxxxxxxxxx.apps.googleusercontent.com",
'client_secret': "xxxxxxxxxxxx",
'redirect_uri': redirect_url,
'grant_type': 'authorization_code'}
print("%^" * 10, json.dumps(data))
r = requests.post('https://www.googleapis.com/oauth2/v3/token', data=json.dumps(data))
print("%" * 10, r.text)
return flask.redirect(redirect_url)
What am I doing wrong? And if there's another way kindly enlighten me.
Once you call oauth2_flow.fetch_token(authorization_response=flask.request.url) you just exchanged the authorization code in that response for an access token.
So you don't need to call the token endpoint, you just need to get credentials:
credentials = oauth2_flow.credentials
And finally get token and refresh_token from credentials.token and credentials.refresh_token.
Take a look on this documentation.
I hope it's clear!
I am trying to short an URL using Google API but using only the requests module.
The code looks like this:
import requests
Key = "" # found in https://developers.google.com/url-shortener/v1/getting_started#APIKey
api = "https://www.googleapis.com/urlshortener/v1/url"
target = "http://www.google.com/"
def goo_shorten_url(url=target):
payload = {'longUrl': url, "key":Key}
r = requests.post(api, params=payload)
print(r.text)
When I run goo_shorten_url it returns:
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Required",
"locationType": "parameter",
"location": "resource.longUrl"
}
],
"code": 400,
"message": "Required"
}
But the longUrl parameter is there!
What am I doing wrong?
At first, please confirm that "urlshortener api v1" is enabled at Google API Console.
Content-Type is required as a header. And please use data as a request parameter. The modified sample is as follows.
Modified sample :
import json
import requests
Key = "" # found in https://developers.google.com/url-shortener/v1/getting_started#APIKey
api = "https://www.googleapis.com/urlshortener/v1/url"
target = "http://www.google.com/"
def goo_shorten_url(url=target):
headers = {"Content-Type": "application/json"}
payload = {'longUrl': url, "key":Key}
r = requests.post(api, headers=headers, data=json.dumps(payload))
print(r.text)
If above script doesn't work, please use an access token. The scope is https://www.googleapis.com/auth/urlshortener. In the case of use of access token, the sample script is as follows.
Sample script :
import json
import requests
headers = {
"Authorization": "Bearer " + "access token",
"Content-Type": "application/json"
}
payload = {"longUrl": "http://www.google.com/"}
r = requests.post(
"https://www.googleapis.com/urlshortener/v1/url",
headers=headers,
data=json.dumps(payload)
)
print(r.text)
Result :
{
"kind": "urlshortener#url",
"id": "https://goo.gl/#####",
"longUrl": "http://www.google.com/"
}
Added 1 :
In the case of use tinyurl.com
import requests
URL = "http://www.google.com/"
r = requests.get("http://tinyurl.com/" + "api-create.php?url=" + URL)
print(r.text)
Added 2 :
How to use Python Quickstart
You can use Python Quickstart. If you don't have "google-api-python-client", please install it. After installed it, please copy paste a sample script from "Step 3: Set up the sample", and create it as a python script. Modification points are following 2 parts.
1. Scope
Before :
SCOPES = 'https://www.googleapis.com/auth/drive.metadata.readonly'
After :
SCOPES = 'https://www.googleapis.com/auth/urlshortener'
2. Script
Before :
def main():
"""Shows basic usage of the Google Drive API.
Creates a Google Drive API service object and outputs the names and IDs
for up to 10 files.
"""
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('drive', 'v3', http=http)
results = service.files().list(
pageSize=10,fields="nextPageToken, files(id, name)").execute()
items = results.get('files', [])
if not items:
print('No files found.')
else:
print('Files:')
for item in items:
print('{0} ({1})'.format(item['name'], item['id']))
After :
def main():
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('urlshortener', 'v1', http=http)
resp = service.url().insert(body={'longUrl': 'http://www.google.com/'}).execute()
print(resp)
After done the above modifications, please execute the sample script. You can get the short URL.
I am convinced that one CANNOT use ONLY requests to use google api for shorten an url.
Below I wrote the solution I ended up with,
It works, but it uses google api, which is ok, but I cannot find much documentation or examples about it (Not as much as I wanted).
To run the code remember to install google api for python first with
pip install google-api-python-client, then:
import json
from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build
scopes = ['https://www.googleapis.com/auth/urlshortener']
path_to_json = "PATH_TO_JSON"
#Get the JSON file from Google Api [Website]
(https://console.developers.google.com/apis/credentials), then:
# 1. Click on Create Credentials.
# 2. Select "SERVICE ACCOUNT KEY".
# 3. Create or select a Service Account and
# 4. save the JSON file.
credentials = ServiceAccountCredentials.from_json_keyfile_name(path_to_json, scopes)
short = build("urlshortener", "v1",credentials=credentials)
request = short.url().insert(body={"longUrl":"www.google.com"})
print(request.execute())
I adapted this from Google's Manual Page.
The reason it has to be so complicated (more than I expected at first at least) is to avoid the OAuth2 authentication that requires the user (Me in this case) to press a button (to confirm that I can use my information).
As the question is not very clear this answer is divided in 4 parts.
Shortening URL Using:
1. API Key.
2. Access Token
3. Service Account
4. Simpler solution with TinyUrl.
API Key
At first, please confirm that "urlshortener api v1" is enabled at Google API Console.
Content-Type is required as a header. And please use data as a request parameter. The modified sample is as follows.
(Seems not to be working despite what the API manual says).
Modified sample :
import json
import requests
Key = "" # found in https://developers.google.com/url-shortener/v1/getting_started#APIKey
api = "https://www.googleapis.com/urlshortener/v1/url"
target = "http://www.google.com/"
def goo_shorten_url(url=target):
headers = {"Content-Type": "application/json"}
payload = {'longUrl': url, "key":Key}
r = requests.post(api, headers=headers, data=json.dumps(payload))
print(r.text)
Access Token:
If above script doesn't work, please use an access token. The scope is https://www.googleapis.com/auth/urlshortener. In the case of use of access token, the sample script is as follows.
This answer in Stackoverflow shows how to get an Access Token: Link.
Sample script :
import json
import requests
headers = {
"Authorization": "Bearer " + "access token",
"Content-Type": "application/json"
}
payload = {"longUrl": "http://www.google.com/"}
r = requests.post(
"https://www.googleapis.com/urlshortener/v1/url",
headers=headers,
data=json.dumps(payload)
)
print(r.text)
Result :
{
"kind": "urlshortener#url",
"id": "https://goo.gl/#####",
"longUrl": "http://www.google.com/"
}
Using Service Account
To avoid the user need to accept the OAuth authentication (with a pop up screen and all that) there is a solution that uses authentication from machine to machine using a Service Account (As mentioned in another proposed answer).
To run this part of the code remember to install google api for python first with pip install google-api-python-client, then:
import json
from oauth2client.service_account import ServiceAccountCredentials
from apiclient.discovery import build
scopes = ['https://www.googleapis.com/auth/urlshortener']
path_to_json = "PATH_TO_JSON"
#Get the JSON file from Google Api [Website]
(https://console.developers.google.com/apis/credentials), then:
# 1. Click on Create Credentials.
# 2. Select "SERVICE ACCOUNT KEY".
# 3. Create or select a Service Account and
# 4. save the JSON file.
credentials = ServiceAccountCredentials.from_json_keyfile_name(path_to_json, scopes)
short = build("urlshortener", "v1",credentials=credentials)
request = short.url().insert(body={"longUrl":"www.google.com"})
print(request.execute())
Adapted from Google's Manual Page.
Even simpler:
In the case of use tinyurl.com
import requests
URL = "http://www.google.com/"
r = requests.get("http://tinyurl.com/" + "api-create.php?url=" + URL)
print(r.text)