How can I download a file from an Autodesk A360 bucket that I created? The file is a Revit project file and I used 2-legged OAuth for authorization.
You need to use 3 legged authentication to access files from A360, because you need the approval of the user whose account you are accessing - the user is the 3rd leg.
If you are trying to access files from your own application's private bucket on OSS then you do not need a user's approval because the bucket belongs to your app and not a user.
As a side note, in case of trying to access BIM 360 files (in case that's what you are talking about) using the Data Management API, then for the time being you need to use 2 legged authentication but your app needs to be manually approved by us.
2-legged vs 3-legged authentication is covered by Augusto's webcast:
Introduction to oAuth and Data Management API
I don't get a bucket key after attempting to create a bucket in when i change v1 to v2...
see below
public static string GetBucket(string accessToken, string bucketKey, string policy)
{
// (1) Build request
var client = new RestClient();
client.BaseUrl = new System.Uri(baseApiUrl);
// Set resource/end point
var request = new RestRequest();
request.Resource = "oss/v1/buckets";
request.Method = Method.GET;
// Add headers
request.AddHeader("Authorization", "Bearer " + accessToken);
request.AddHeader("Content-Type", "application/json"); // MH: skipping this works.
// Add JSON body. in simplest form.
request.AddJsonBody(new { bucketKey = bucketKey, policy = policy });
// (2) Execute request and get response
IRestResponse response = client.Execute(request);
//TaskDialog.Show("create bucket", response.StatusDescription);
// Save response. This is to see the response for our learning.
m_lastResponse = response;
TaskDialog.Show("response", m_lastResponse.ToString());
// Get the key = bucket name
string key = "";
if (response.StatusCode == HttpStatusCode.OK)
{
JsonDeserializer deserial = new JsonDeserializer();
OssBucketsResponse bucketsResponse = deserial.Deserialize<OssBucketsResponse>(response);
key = bucketsResponse.key;
}
return key; // the bucket name
}
Related
I want to write e2e tests that can run in our CI environment which is tightly locked down and has no internet access.
I am using the auth0 react loginWithRedirect function which will attempt to redirect to the auth0 login on their servers and will timeout on CI.
I am able to intercept the call to /authorize in express:
app.get('/auth0/:simulation_id/authorize', middleware, (req, res) => {
const { client_id, redirect_uri, scope, state } = req.query;
Is it now possible for me to generate a mock oauth token that will be accepted by the #auth0/react client code?
Yes. Using the jsrsasign.js library, where accessKey contains a private key:
function createJwt(username, type, realm, scopes, sessionId, expires_in, audience) {
var oHeader = {
alg: 'RS256',
typ: 'JWT'
};
// Payload
var oPayload = {};
var tNow = jwt.KJUR.jws.IntDate.get('now');
var token_expiry = expires_in;
var tEnd = tNow + token_expiry;
oPayload.sub = username;
oPayload.auditTrackingId = uuidv4();
oPayload.iss = "https://mock.org/identities/v1/" + realm + "/token";
oPayload.tokenName = type;
oPayload.token_type = 'Bearer';
oPayload.authGrantId = !sessionId ? uuidv4() : sessionId;
oPayload.aud = (audience ? audience : "https://mock.org/identities/v1/" + realm + "/token");
oPayload.nbf = tNow;
oPayload.scope = scopes;
// oPayload.auth_time = tNow;
oPayload.realm = '/' + realm;
oPayload.exp = tEnd;
oPayload.expires_in = token_expiry * 100000;
oPayload.iat = tNow;
oPayload.jti = uuidv4();
var sHeader = JSON.stringify(oHeader);
var sPayload = JSON.stringify(oPayload);
var prvKey = accessKey;
var sJWT = jwt.KJUR.jws.JWS.sign("RS256", sHeader, sPayload, prvKey);
return sJWT;
}
Set the audience, subject, scp and any other properties in line with the tokens that auth0 is creating.
You also might need to mock out the jwk endpoints, but I doubt the library will care. If it doesn't work it will be due to certain properties not being available on the token.
You might need to create an id token as well, depending on your setup.
Access key is similar to this:
var accessKey = jwt.KEYUTIL.getKey("-----BEGIN PRIVATE KEY-----\n" +
"MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC0g+nePEZ6aFiH\n" +
"ccnle/ryqz1lNvloPGuA5b6GeE8MrT7SATxv54zQ2LnvuRp86cd32elL0YAw3GMc\n" +
... snip ...
"Rno3R82z6SAvy9HgIMzfti5NSVgqC9nmhFEs+ChFWuboGotVV99COVJId9S/567n\n" +
"kz90cLENtD/8JTYAhLea5F/PJBJJHSvQT298ZxR4bw1vQ5Bq2FMnLSYuIOQMkQdr\n" +
"Yqt+8gXW0+3kfyb3cCyI+2HKcQ==\n" +
"-----END PRIVATE KEY-----\n");
And keep going til you've mocked out the entire IdP platform :) (I basically did the same thing with OpenAM a few years ago).
In addition to #stringy05's response; if you've got back-end services (e.g. Java, .NET, etc) that are called by your React app and need to do JWT validation, you might need to statically host your own an OpenID Configuration and JSON Web Key Set endpoints in your own environment.
The reason for this is because JWT validation (by back-end services) would still require communication to the external authorization server. With JWT-based auth this is generally limited to a single (up-front or lazy-loaded) request to get the public key for signature validation, but there could also be additional calls e.g. when the service encounters an unknown kid (key ID) on a JWT, as well as a periodical refresh interval (e.g. daily).
For Auth0 OpenID Configuration and JSON Web Key Set endpoints are hosted at the following locations:
OpenID Configuration: https://[tenant-name].[2-letter-iso-country-code].auth0.com/.well-known/openid-configuration
JSON Web Key Set: https://[tenant-name].[2-letter-iso-country-code].auth0.com/.well-known/jwks.json
These are just static JSON documents. You can probably just copy these from one of your existing tenants, modify accordingly, and then host in your own environment. The modifications you'd need to make include:
OpenID Configuration to reference local jwks_uri endpoint.
Update the key information in the JSON Web Key Set endpoint. Note: you can generate an asymetric key pair using OpenSSL, and see here for information about how to extract modulus and exponent from public key (which are required for the JWKS document). Note: in your React app, you'd need to sign the tokens with the private key that you generate.
Once you've done the above, your back-end services can reference the locally hosted OpenID Configuration and will be able to do JWT validation without communicating to an external authorization server.
I have a Angular 4 site that I’m trying to use Microsoft Graph implicit flow to authenticate users then use token to call our APIs at another endpoint, so I use msal.js to get the access token.
After I bring the access token to my API endpoint and try to valid it, the token cannot be valid. I got a SignatureVerificationFailedException.
My understanding is that the access token is for Microsoft Graph API, not for my APIs, so I cannot valid it. (I can use it to call Graph API without problem)
How can I get a access token(not id token) using msal.js that can be used for my APIs but not Microsoft Graph? Thanks!
The reason I'm sending access token instead of id token to the API endpoint is that I want to get the puid claim from the token, which is not available for id token.
Here is what I was trying to valid the access token I got from client which is using msal.js
const string authority = "https://login.microsoftonline.com/common";
const string audience = "https://graph.microsoft.com";
string issuer = null;
string stsDiscoveryEndpoint = $"{authority}/v2.0/.well-known/openid-configuration";
List<SecurityToken> signingTokens = null;
var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint);
var config = await configManager.GetConfigurationAsync();
issuer = config.Issuer;
signingTokens = config.SigningTokens.ToList();
var tokenHandler = new JwtSecurityTokenHandler();
var validationParameters = new TokenValidationParameters
{
ValidAudience = audience,
ValidIssuer = issuer,
ValidateIssuer = false,
IssuerSigningTokens = signingTokens,
CertificateValidator = X509CertificateValidator.None
};
try
{
// Validate token.
SecurityToken validatedToken = new JwtSecurityToken();
var claimsPrincipal = tokenHandler.ValidateToken(jwtToken, validationParameters, out validatedToken);
var claimsIdentity = claimsPrincipal.Identity as ClaimsIdentity;
return ExtractAuthenticatedUserFromClaimsIdentity(claimsIdentity);
}
catch (SignatureVerificationFailedException)
{
throw;
}
Thanks,
If you want to get an access token for your API rather than the Microsoft Graph API, you must specify your API as the resource in the token request.
Make sure that:
Your Web API has configured OAuth2Permission Scopes. See here. Configuring a resource application to expose web APIs
Your Client Application has selected permissions to those exposed APIs. Configuring a client application to access web APIs
Finally, make sure you use your Web API's App ID URI or App ID GUID as the resource value in your token request.
Let me know if this helps!
I am writing some code to try to get a token to use from Google in OAuth2. This is for a service account, so the instructions are here:
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
I keep getting this error when I post the JWT to Google:
{ "error": "invalid_grant", "error_description": "Invalid JWT Signature." }
Here is the code:
try{
var nowInSeconds : Number = (Date.now() / 1000);
nowInSeconds = Math.round(nowInSeconds);
var fiftyNineMinutesFromNowInSeconds : Number = nowInSeconds + (59 * 60);
var claimSet : Object = {};
claimSet.iss = "{{RemovedForPrivacy}}";
claimSet.scope = "https://www.googleapis.com/auth/plus.business.manage";
claimSet.aud = "https://www.googleapis.com/oauth2/v4/token";
claimSet.iat = nowInSeconds;
claimSet.exp = fiftyNineMinutesFromNowInSeconds;
var header : Object = {};
header.alg = "RS256";
header.typ = "JWT";
/* Stringify These */
var claimSetString = JSON.stringify(claimSet);
var headerString = JSON.stringify(header);
/* Base64 Encode These */
var claimSetBaseSixtyFour = StringUtils.encodeBase64(claimSetString);
var headerBaseSixtyFour = StringUtils.encodeBase64(headerString);
var privateKey = "{{RemovedForPrivacy}}";
/* Create the signature */
var signature : Signature = Signature();
signature = signature.sign(headerBaseSixtyFour + "." + claimSetBaseSixtyFour, privateKey , "SHA256withRSA");
/* Concatenate the whole JWT */
var JWT = headerBaseSixtyFour + "." + claimSetBaseSixtyFour + "." + signature;
/* Set Grant Type */
var grantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
/* Create and encode the body of the token post request */
var assertions : String = "grant_type=" + dw.crypto.Encoding.toURI(grantType) + "&assertion=" + dw.crypto.Encoding.toURI(JWT);
/* Connect to Google And Ask for Token */
/* TODO Upload Certs? */
var httpClient : HTTPClient = new HTTPClient();
httpClient.setRequestHeader("content-type", "application/x-www-form-urlencoded; charset=utf-8");
httpClient.timeout = 30000;
httpClient.open('POST', "https://www.googleapis.com/oauth2/v4/token");
httpClient.send(assertions);
if (httpClient.statusCode == 200) {
//nothing
} else {
pdict.errorMessage = httpClient.errorText;
}
}
catch(e){
Logger.error("The error with the OAuth Token Generator is --> " + e);
}
Does anyone know why the JWT is failing?
Thanks so much!
Brad
The problem might be related to the fact that your StringUtils.encodeBase64() method is likely to perform a standard base64 encoding.
According to the JWT spec, however, it's not the standard base64 encoding that needs to be used, but the the URL- and filename-safe Base64 encoding, with the = padding characters omitted.
If you don't have a utility method handy for base64URL encoding, you can verify by
replacing all + with -;
replacing all / with _;
removing all =
in your base64-encoded strings.
Also, is your signature also base64-encoded? It needs to be, following the same rules as described above.
I had the same problem before and this is what was wrong:
wrong application name (project ID)
wrong service account ID (email)
The another reason for this error could be "Your service account is not activated", With gsutil installed from the Cloud SDK, you should authenticate with service account credentials.
1- Use an existing service account or create a new one, and download the associated private key.
2- Use gcloud auth activate-service-account to authenticate with the service account:
gcloud auth activate-service-account --key-file [KEY_FILE]
Where [KEY_FILE] is the name of the file that contains your service account credentials.
Link for more detail: Activate service account
This could also happen if a developer mistakenly copies, edits, and uses a service account key file for a purpose other than the one for which the file was originally intended. For example:
Developer A creates SA 1
Developer A uses gcloud iam service-accounts keys create ... to create the secret file for SA 1, encrypts it, and checks it in to source control
Developer B creates SA 2
Developer B (mistakenly) decrypts and copies the secret file from step 2, modifies some of its fields with data from SA 2, then attempts to use it in an application
The resolution in this scenario obviously is for Developer B to get rid of the copied/edited file and create a new secret file with gcloud like Developer A did in step 2.
I had this same error occur when using a service account. I couldn't figure out what was wrong so I came back to it the next day and it worked. So maybe Google Cloud takes some time to propagate every once in a while.
I've been trying to integrate the Instagram API in my app, but am stuck with the authentication. I had it working completely fine when I was just using the implicit flow version which gave me the access_token as part of the URI fragment.
However, now I'm changing to the server-side flow, in which I receive a code after the user logs in. I then post this code to the access token URL, which will then give me the access_token as well as certain information about the user, such as their username and profile picture link.
I am using the InstaSharp library, modifying the source code.
HttpClient client = new HttpClient { BaseAddress = new Uri(config.OAuthUri + "access_token/", UriKind.Absolute) };
var request = new HttpRequestMessage(HttpMethod.Post, client.BaseAddress);
request.AddParameter("client_secret", config.ClientSecret);
request.AddParameter("client_id", config.ClientId);
request.AddParameter("grant_type", "authorization_code");
request.AddParameter("redirect_uri", config.RedirectUri);
request.AddParameter("code", code);
return client.ExecuteAsync<OAuthResponse>(request);
After creating my request, it is formatted as so:
{Method: POST, RequestUri: 'https://api.instagram.com/oauth/access_token/?client_secret={CLIENT_SECRET}&client_id={CLIENT_ID}&grant_type=authorization_code&redirect_uri=http://instagram.com &code={CODE}', Version: 1.1, Content: , Headers: { }}
(I inserted the space between the redirect_uri and code because it wouldn't let me post the question otherwise)
Everything appears normal in the address, but I always receive an error in the retuned json file:
"{"code": 400, "error_type": "OAuthException", "error_message": "You must provide a client_id"}"
I have no clue what is causing this error. Any help is greatly appreciated!
Thanks!
Elliott
Are you using the latest version of InstaSharp? Fork it here. You can check the README.md there although it's a bit outdated and you need to tweak some config. Here's how you can do it with the latest version that is in github:
// create the configuration in a place where it's more appropriate in your app
InstaSharpConfig = new InstagramConfig(
apiURI, oauthURI, clientId, clientSecret, redirectUri);
// then here's a sample method you can have to initiate auth
// and catch the redirect from Instagram
public ActionResult instagramauth(string code)
{
if (string.IsNullOrWhiteSpace(code))
{
var scopes = new List<InstaSharp.Auth.Scope>();
scopes.Add(InstaSharp.Auth.Scope.likes);
var link = InstaSharp.Auth.AuthLink(
oauthURI, clientId, redirectUri, scopes);
// where:
// oauthURI is https://api.instagram.com/oauth
// clientId is in your Instagram account
// redirectUri is the one you set in your Instagram account;
// for ex: http://yourdomain.com/instagramauth
return Redirect(link);
}
// add this code to the auth object
var auth = new InstaSharp.Auth(InstaSharpConfig);
// now we have to call back to instagram and include the code they gave us
// along with our client secret
var oauthResponse = auth.RequestToken(code);
// save oauthResponse in session or database, whatever suits your case
// oauthResponse contains the field Access_Token (self-explanatory),
// and "User" that'll give you the user's full name, id,
// profile pic and username
return RedirectToAction("action", "controller");
}
Take note that you can split up the "instagramauth" method. Did it that way for brevity.
I am struggling to get this done, I need to connect to twitter rest Api 1.1 to get user details, time line etc.
What I came across is:
I have a Twitter App with access token ,secrete etc.
Now how to use all that access token etc to send (GET or POST) request to Twitter from Salesforce. How to set header or how to authenticate request.
A tutorial would be very help full all I could find was tutorials for php etc I need it for "salesforce"
Note: I don't want to use a external lib
You should be able to do this directly from Apex using the HTTP REST library. Here is the first Google result for "salesforce apex twitter integration" with this sample code from Navatar_DbSup:
VF CODE:
<apex:inputTextarea id="tweetInput" onkeyup="return maxLength();" onKeyPress="return maxLength();" value="{!newTweet}" rows="2" cols="73"/>
<apex:commandButton id="tweetBtn" style="height:35px;" value="Tweet" action="{!postTweet}" />
Controller code:
*** post tweets into twitter*/
public String newTweet{get;set;}
public Void postTweet()
{
Http h = new Http();
HttpRequest req = new HttpRequest();
Method = 'POST';
req.setMethod(Method);
req.setEndpoint('https://api.twitter.com/1/statuses/update.xml');
newTweet = newTweet.replace('%','%25').replace('&','%26').replace('#','%40').replace(';','%3B').replace('?','%3F').replace('/','%2F').replace(':','%3A').replace('#','%23').replace('=','%3D').replace('+','%2B').replace('$','%24').replace(',','%2C').replace(' ','%20').replace('<','%3C').replace('>','%3E').replace('{','%7B').replace('}','%7D').replace('[','%5B').replace(']','%5D').replace('`','%60').replace('|','%7C').replace('\\','%5C').replace('^','%5E').replace('"','%22').replace('\'','%27').replace('!','%21').replace('*','%2A').replace('(','%28').replace(')','%29').replace('~','%7F');
req.setBody('status='+newTweet);
req.setHeader('Content-Type','application/x-www-form-urlencoded');
OAuth oa = new OAuth();
if(!oa.setService())
{
message=oa.message;
}
oa.sign(req);
HttpResponse res = h.send(req);
system.debug('&&&&&&&&&&&&&&&&7' + res.getBody());
PostTweetbody = res.getBody() + '___' + message;
newTweet = '';
}