I am trying to run Microsoft graph API to generate token. This is working fine in postman but failed in SoapUI. I think client secret has special characters which are causing the issue.
client secret:
osi5oX-:?0A3YiG4aCpZ.Y[+PW51pZVY
API URL (POST) :
https://login.microsoftonline.com/{tenantID}/oauth2/v2.0/token
Body:
client_id=xxxxx&client_secret=osi5oX-:?0A3YiG4aCpZ.Y[+PW51pZVY&grant_type=client_credentials&scope=https://graph.microsoft.com/.default
Error:
{"error":"invalid_client","error_description":"AADSTS7000215: Invalid client secret is provided.\r\nTrace ID: 32b5bf83-f908-4b4e-9fe6-5b05fd949e00\r\nCorrelation ID: b9b7ce92-f5d1-41d1-8d92-eed8a6a5470b\r\nTimestamp: 2020-05-07 17:27:08Z","error_codes":[7000215],"timestamp":"2020-05-07 17:27:08Z","trace_id":"32b5bf83-f908-4b4e-9fe6-5b05fd949e00","correlation_id":"b9b7ce92-f5d1-41d1-8d92-eed8a6a5470b","error_uri":"https://login.microsoftonline.com/error?code=7000215"}
Use secret after encoding and it works.
import java.net.URLEncoder;
String url = "osi5oX-:?0A3YiG4aCpZ.Y[+PW51pZVY"
String encodedUrl = URLEncoder.encode(url, "UTF-8" );
println(encodedUrl)
Related
I tried to receive a token with the code below. Unfortunatelly I get the error:
DocuSign.eSign.Client.ApiException
HResult=0x80131500
Nachricht = Error while requesting server, received a non successful HTTP code with response Body: {"error":"consent_required"}
I tried with set TLS 12 and without. We run it in dev mode with base path https://demo.docusign.net/restapi
and oAuthBasePath =account-d.docusign.com
I tried also to set the consens manually with the URL below. But I receive the error in (Login Window) invalid Authorization: RequestType is not supported.
https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation&client_id=a5ed47d5-xxxx-xxxx-8a19-756da64391de&redirect_uri=https://www.docusign.com
Is the something wrong with my account setting?
byte[] privateKey=DSHelper.ReadFileContent(DSHelper.PrepareFullPrivateKeyFilePath(privateKeyFilename));
var scopes = new List<string>
{
"signature",
"impersonation",
};
var basePath = ApiClient.Production_REST_BasePath;
var oAuthBasePath = OAuth.Production_OAuth_BasePath;
if (!production)
{
basePath = ApiClient.Demo_REST_BasePath;
oAuthBasePath = OAuth.Demo_OAuth_BasePath;
}
var _apiClient = new ApiClient(basePath);
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var authToken = _apiClient.RequestJWTUserToken(
clientId,
ImpersonatedUserId,
oAuthBasePath,
privateKey,
1,
scopes);
I found the solution. instead of reponse_type= code I have to use token
What response_type is supported for an integration key depends on how the key is configured. In the Authentication section of the key's configuration panel, Auth Code Grant allows the response type of code, while Implicit Grant allows the response type of token.
DocuSign's authentication docs assume you have "Auth Code Grant" selected, but either is technically acceptable to allow JWT consent.
I need to create service that calls graph api to access company data. In order to authenticate I need JWT token from Azure Active Directory. The authentication will be using application mode with signing certificate. I tried to use MSAL node ConfidentialClientApplication but the service needs to use http proxy to connect to internet. To my knowledge MSAL node does not support this and calls result in library being unable to resolve the address of "https://login.microsoftonline.com". How can I make MSAL node use the proxy or get JWT token without use od MSAL?
In order to get JWT token from azure active directory without MSAL node, one have to generate proper JWT token on its own and then sign it with certificate private key. The header of the token consists of following fields:
{
typ: "JWT",
alg: "RS256",
kid: "156E...",
x5t: "iTYVn..."
}
"kid" is the thumbprint of the certificate used to sign the request - here is a good example how to obtain it for pfx file with powershell https://stackoverflow.com/a/32980899/3588432
"x5t" is base64 encoded and sanitized certificate thumbprint.
Sanitization of base64 encoded string means:
trimming "=" signs at the end
replace "/" with "_"
replace "+" with "-"
Exemplary C# code for the sanitization:
var sanitized = s.Split('=')[0].Replace('+', '-').Replace('/', '_');
and JS code:
var sanitized = s.split('=')[0].replace('+', '-').replace('/', '_');
The payload of the token consists of the following fields:
{
aud: "https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token",
iss: "{clientId}",
nbf: 1617952610,
exp: 1617953210,
sub: "{clientId}",
jti: "e13efcf..."
}
{tenantId} and {clientId} are Azure AD data of application we are authenticating to
"nbf" is the time when the token will began to be valid, normally it is time the token got generated. It has unix epoch format https://en.wikipedia.org/wiki/Unix_time and is an integer.
"exp" - the time the token expires in unix epoch format.
"jti" - a unique token identifier. It may be random generated guid. Should be different for every request.
An example how to get "nbf" value in JavaScript:
var nbf = Math.floor(new Date().getTime() / 1000);
When ready header and payload should be serialized (with sanitization) on concatenated with ".":
var token = JSON.stringify(header) + "." + JSON.stringify(payload);
Then we need to sign it with certificate private key, encode it with base 64 (with sanitization) and prepare a clientAssertion value:
var clientAssertion = token + "." + signedToken;
As a last step can send request to get JWT token:
const body = new URLSearchParams();
const token = await fetch("https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token", {
agent: new HttpsProxyAgent("http://..."),
body: new URLSearchParams({
"client_assertion": clientAssertion,
"client_id": "{clientId}",
"scope": "https://graph.microsoft.com/.default"
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
"grant_type": "client_credentials"
}),
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded"
}
})
.then(response => response.json().access_token);
I have a bot in NodeJS connected to Google Chat using HTTPs endpoints. I am using express to receive requests. I need to verify that all requests come from Google, and want to do this using the Bearer Token that Google Sends with requests.
My problem is that I am struggling to find a way to verify the tokens.
I have captured the token and tried a GET reuqes to https://oauth2.googleapis.com/tokeninfo?id_token=ey... (where ey... is the token start).
Which returns:
"error": "invalid_token",
"error_description": "Invalid Value"
}
I have tried what Google recommends:
var token = req.headers.authorization.split(/[ ]+/);
client.verifyIdToken({
idToken: token[1],
audience: JSON.parse(process.env.valid_client_ids)
}).then((ticket) => {
gchatHandler.handleGChat(req.body, res);
}).catch(console.error);
And get the following error:
Error: No pem found for envelope: {"alg":"RS256","kid":"d...1","typ":"JWT"}
Any idea where I should head from here?
Edit: https://www.googleapis.com/service_accounts/v1/metadata/x509/chat#system.gserviceaccount.com found this, investigating how to use it. The kid matches the one I get.
Worked it out, eventually.
You need to hit: https://www.googleapis.com/service_accounts/v1/metadata/x509/chat#system.gserviceaccount.com to get a JSON file containing the keys linked to their KIDs.
Then when a request arrives, use jsonwebtoken (NPM) to decode the token and extract the KID from the header.
Use the KID to find the matching public key in the response from the website above, then use the verify function to make sure the token matches the public key.
You also need to pass the audience and issuer options to verify, to validate that it is your particular service account hitting the bot.
The solution above maybe the correct for Google Chat, but in my experience Google services (e.g. Google Tasks) use OIDC tokens, which can be validated with verifyIdToken function.
Adding my solution here, since your question/answer was the closest thing I was able to find to my problem
So, In case if you need to sign a request from your own code
on client, send requests with OIDC token
import {URL} from 'url';
import {GoogleAuth} from 'google-auth-library';
// will use default auth or GOOGLE_APPLICATION_CREDENTIALS path to SA file
// you must validate email of this identity on the server!
const auth = new GoogleAuth({});
export const request = async ({url, ...options}) => {
const targetAudience = new URL(url as string).origin;
const client = await auth.getIdTokenClient(targetAudience);
return await client.request({...options, url});
};
await request({ url: 'https://my-domain.com/endpoint1', method: 'POST', data: {} })
on the server, validate OIDC (Id token)
const auth = new OAuth2Client();
const audience = 'https://my-domain.com';
// to validate
const token = req.headers.authorization.split(/[ ]+/)[1];
const ticket = await auth.verifyIdToken({idToken: token, audience });
if (ticket.getPayload().email !== SA_EMAIL) {
throw new Error('request was signed with different SA');
}
// all good
Read more about Google OpenID Connect Tokens
I am trying to access an Azure Function from Dynamics 365 Plugin via service to service call: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service
This function is protected via App Service Authentication.
I created a Function App and enabled App Service Authentication
under Platform Features -> Authentication/Authorisation.
I enabled Azure Active Directory as the Auth Provider and set Management mode to Express
I then got the generated Client ID and Client Secret from the Advanced Mode:
Apparently this is all that is needed to make a token request for the Azure function based, based on article I need 4 required parameters:
Client ID
Client Secret
Grant Type
Resource
I make the following request to generate a token from a Dynamics 365 Plugin but get the following error:
Invalid Plugin Execution Exception: Microsoft.Xrm.Sdk.InvalidPluginExecutionException: {"error":"invalid_client","error_description":"AADSTS70002: Error validating credentials. AADSTS50012: Invalid client secret is provided.\r\nTrace ID: 06ddda7f-2996-4c9b-ab7e-b685ee933700\r\nCorrelation ID: d582e2f2-91eb-4595-b44b-e95f42f2f071\r\nTimestamp: 2018-05-23 06:30:58Z","error_codes":[70002,50012],"timestamp":"2018-05-23 06:30:58Z","trace_id":"06ddda7f-2996-4c9b-ab7e-b685ee933700","correlation_id":"d582e2f2-91eb-4595-b44b-e95f42f2f071"}-The remote server returned an error: (401) Unauthorized.
My code is :
var tokenendpoint = "https://login.microsoftonline.com/de194c13-5ff7-4085-91c3-ac06fb869f28/oauth2/token";
var reqstring = "client_id=" + Uri.EscapeDataString("5f315431-e4da-4f68-be77-4e257b1b9295");
reqstring += "&client_secret=" + Uri.EscapeDataString("/oK7nh8pl+LImBxjm+L7WsQdyILErysOdjpzvA9g9JA=");
reqstring += "&resource=" + Uri.EscapeUriString("https://keyvaultaccess.azurewebsites.net");
reqstring += "&grant_type=client_credentials";
//Token request
WebRequest req = WebRequest.Create(tokenendpoint);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(reqstring);
req.ContentLength = bytes.Length;
System.IO.Stream os = req.GetRequestStream();
os.Write(bytes, 0, bytes.Length);
os.Close();
//Token response
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
StreamReader tokenreader = new StreamReader(resp.GetResponseStream());
string responseBody = tokenreader.ReadToEnd();
I have made sure that I have the correct Client Secret and have also encoded it as I have read somewhere that '+' and '/' are no good.
I am getting the same error in Postman
Any ideas??
reqstring += "&resource=" + Uri.EscapeUriString("https://keyvaultaccess.azurewebsites.net");
Since you set resource parameter to https://keyvaultaccess.azurewebsites.net, I assumed that you have set the App ID URI of your AAD app (clientId equals 5f315431-xxxxxxx-4e257b1b9295) to https://keyvaultaccess.azurewebsites.net. I assume that you could retrieve the access_token, but when accessing your azure function endpoint with the access_token, you got the 401 status code.
You need to modify your advanced management mode for Active Directory Authentication, add https://keyvaultaccess.azurewebsites.net to ALLOWED TOKEN AUDIENCES or change the resource parameter to your AAD clientID when sending the token request for acquiring the access_token.
Active Directory Authentication configuration:
TEST:
Docode the JWT token to check the aud property:
Access my Azure Function endpoint:
Note: You need to take care of the Authorization level of your function as follows:
If you also enable function level authentication, your request sent to azure function needs to have the relevant code parameter in the querystring or set the header x-functions-key with the value of your function key, or you may just set the authorization level to Anonymous.
After following the guide for creating a custom identity provider for azure mobile services I can easily generate the appropriate tokens. The code is pretty simple and looks like this:
var userAuth = {
user: { userId : userId },
token: zumoJwt(expiry, aud, userId, masterKey)
}
response.send(200, userAuth);
The definitions for the parameters and code for zumoJwt are located at the link. Azure automatically decodes the token and populates the user on the request object which is what I'd like to simulate.
Basically I'd like to to decrypt the token on the serverside via Node (not .net).
What I ended up doing to validate the token is the following (boiled down). This seems to be about what the azure mobile services is doing on routes that require authorization.
var jws = require('jsw'); // https://github.com/brianloveswords/node-jws
function userAuth() {
var token = ''; // get token as header or whatever
var key = crypto.createHash('sha256').update(global.masterKey + "JWTSig").digest('binary');
if (!jws.verify(token,key)) {
// invalid token logic
} else {
var decode = jws.decode(token)
req.user = {
userId: decode.payload.uid.split(';')[0].split('::')[0]
};
next();
}
}
app.use(authChecker);
The tokens aren't really encrypted - they're just signed. The tokens have the JWT format (line breaks added for clarity):
<header>, base64-encoded
"."
<envelope>, base64-encoded
"."
<signature>, base64-encoded
If you want to decode (not decrypt) the token in node, you can split the value in the . character, take the first two members, base64-decode them (var buffer = new Buffer(part, 'base64')), and convert the buffer to string (buffer.toString('utf-8')).
If you want to validate the token, just follow the same steps you need to re-sign the first two parts of the token (header + '.' + envelope) with the master key, in the same way that the token was created, and compare it with the signature you received on the original token.