I'm creating application with Blazor in NET6. To call the API via an Azure API Management, I have to pass a token in the request adding
request.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
In this request, I have to pass the token that comes from an Identity Server. So, first, the user has to authenticate to the identity server and then receives the JWT token.
The configuration is
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("oidc", options.ProviderOptions);
options.UserOptions.RoleClaim = "role";
})
.AddAccountClaimsPrincipalFactory<MultipleRoleClaimsPrincipalFactory<RemoteUserAccount>>();
builder.Services.AddAuthorizationCore();
Also, to apply the security, I add in the Program.cs this lines
app.Use((context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
MustRevalidate = true,
NoCache = true,
NoStore = true,
};
string oidcAuthority = builder.Configuration.GetValue(typeof(string), "oidc:Authority").ToString();
string mainUrl = "https://test.mywebsite.com/";
#if DEBUG
mainUrl = "https://localhost:7040";
#endif
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("Content-Security-Policy",
$"default-src 'self' {mainUrl} {oidcAuthority} " +
"https://code.cdn.mozilla.net " +
#if DEBUG
"https://dc.services.visualstudio.com " +
#endif
"https://api.myapi.com " +
"'unsafe-inline' 'unsafe-eval'; " +
$"script-src 'self' {mainUrl} 'unsafe-inline' 'unsafe-eval'; " +
$"connect-src 'self' {oidcAuthority} https://code.cdn.mozilla.net https://api.myapi.com;" +
$"img-src 'self' {mainUrl} data:; " +
$"style-src 'unsafe-inline' {mainUrl} " +
"https://code.cdn.mozilla.net " +
";" +
"base-uri 'self'; " +
"form-action 'self'; " +
"frame-ancestors 'self';");
context.Response.Headers.Add("Referrer-Policy", "same-origin");
context.Response.Headers.Add("Permissions-Policy", "geolocation=(), microphone=()");
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
context.Response.Headers.Add("SameSite", "Strict");
return next.Invoke();
});
So, after that I can read the JWT token with this code:
IAccessTokenProvider _accessToken;
private async Task<AccessToken> RequestUserToken()
{
try
{
var tokenResult = await _accessToken.RequestAccessToken();
tokenResult.TryGetToken(out var token);
Console.WriteLine(token);
return token;
}
catch (AccessTokenNotAvailableException aex)
{
throw new ApplicationException($"Exception {aex}");
}
catch (Exception ex)
{
throw new ApplicationException(
$"AccessTokenNotAvailable Exception Exception {ex}");
}
}
The application is working on Windows for any browser. On iOS and macOS I can read the token if I use Safari. It is working if I use Microsoft Edge and Chrome.
Do you have any idea how can I fix it?
Related
I am using cordova-plugin-advanced-http plugin for API calling and all JSON enabled API working fine but I have one XML embedded API which is working fine in Postman but while I call it from ionic its param not getting at the server end.
Below is my code for XML API:
Type 1:
let headers = {
"Content-type": 'text/xml; charset=utf-8',
"Authorization": token,
};
let xmlBody =
'<ServiceRequest>' +
'<CaseNumber>' + caseNumber +
'</CaseNumber>' +
'</ServiceRequest>'
this.httpPlugin.setDataSerializer('utf8');
this.httpPlugin.post('https://test.com/Service', xmlBody, headers).then((response) => {
console.log("XML Response : ", JSON.stringify(response.data));
xml2js.parseString(response.data, function (err, result) {
console.log("XML parser success:", result);
console.log("XML parser error:", err);
if (result) {
resolve(result);
} else {
reject(err);
}
});
}).catch(error => {
if (error.status == 403) {
console.log("Token expired : " + JSON.stringify(error));
} else {
console.log("Error : " + error.error);
console.log("Error " + JSON.stringify(error));
reject(error);
}
});
Type 2:
let xmlBody = '<ServiceRequest>' +
'<CaseNumber>' + caseNumber +
'</CaseNumber>' +
'</ServiceRequest>';
console.log("XML Body", xmlBody)
// this.httpPlugin.setRequestTimeout(60);
this.httpPlugin.setDataSerializer('utf8');
this.httpPlugin.setHeader('*', 'authorization', token);
this.httpPlugin.setHeader('*', 'Content-Type', "application/x-www-form-urlencoded");
this.httpPlugin.post('https://test.com/Service', xmlBody, {}).then((response) => {
console.log("XML Response : ", JSON.stringify(response.data));
xml2js.parseString(response.data, function (err, result) {
console.log("XML parser success:", result);
console.log("XML parser error:", err);
if (result) {
resolve(result);
} else {
reject(err);
}
});
}).catch(error => {
if (error.status == 403) {
console.log("Token expired : " + JSON.stringify(error));
} else {
console.log("Error : " + error.error);
console.log("Error " + JSON.stringify(error));
reject(error);
}
});
All the time it's throwing errors from the server and with the same request, I am able to get data in postman as well as Native iOS code.
I referred this issue on GitHub but still no success.
Something I am missing though it's not able to get data on the server.
Help me to solve this issue.
After struggling a lot on this issue I found a solution to clean my request cookies.
In the HTTP Advanced plugin, there is one method to clear my cookies.
clearCookies()
Clear all cookies.
Use this method before calling any API.
So what it will do clear all my cookies and my issue related to old cookies will be solved in this way.
constructor(
public storage: Storage,
public httpPlugin: HTTP,
private platform: Platform
) {
// enable SSL pinning
httpPlugin.setSSLCertMode("pinned");
//Clear old cookies
httpPlugin.clearCookies();
}
The above code solves my issue.
Thanks all for your quick guidance and suggestions.
comment on this if this is not the right way to clear my old request data.
I am trying to use a social auth (twitter into firebase) on android and I get the error above .
As I understand it there is nothing wrong with my code , just some error in twitter developer platform, I ll post both of them just to be sure
_twitterSignIn = async () => {
context = this
const twitterAccessToken = await getTwitterAccessToken();
const twitterAccessTokenSecret = await getTwitterAccessTokenSecret();
console.log("twitterAccessToken: " + twitterAccessToken + ", twitterAccessTokenSecret: " + twitterAccessTokenSecret);
auth({ consumerKey: Constants.TWITTER_COMSUMER_KEY, consumerSecret: Constants.TWITTER_CONSUMER_SECRET, accessToken: twitterAccessToken, accessTokenSecret: twitterAccessTokenSecret }
, "myapp://twitter", { accessType: "write", forSignIn: false, forceLogin: false, screenName: '' }).then(({ accessToken, accessTokenSecret, id, name }) => {
// context.loginLoader({loading:false})
context.props.updateLoader({ loading: false })
AsyncStorage.setItem(TWITTER_AUTH_TOKEN, accessToken)
AsyncStorage.setItem(TWITTER_AUTH_TOKEN_SECRET, accessTokenSecret)
setTwitterConfig();
}).catch(console.error);
}
PS: I also tryed adding twittersdk:// to callback url ,still doesnt work
I'm trying to get the example code for the file-transfer plugin working, it's taken straight from the Cordova docs:
function downloadFile2() {
window.requestFileSystem(window.TEMPORARY, 5 * 1024 * 1024, function (fs) {
console.log('file system open: ' + fs.name);
// Make sure you add the domain name to the Content-Security-Policy <meta> element.
var url = 'http://cordova.apache.org/static/img/cordova_bot.png';
// Parameters passed to getFile create a new file or return the file if it already exists.
fs.root.getFile('downloaded-image.png', { create: true, exclusive: false }, function (fileEntry) {
download2(fileEntry, url, true);
}, function () { logError('Error creating file'); });
}, function () { logError('Error creating fs'); });
}
function download2(fileEntry, uri, readBinaryData) {
var fileTransfer = new FileTransfer();
var fileURL = fileEntry.toURL();
console.log('Downloading ' + uri + ' to ' + fileURL);
fileTransfer.download(
uri,
fileURL,
function (entry) {
console.log("Successful download...");
console.log("download complete: " + entry.toURL());
if (false && readBinaryData) {
// Read the file...
readBinaryFile(entry);
}
else {
// Or just display it.
displayImageByFileURL(entry);
}
},
function (error) {
console.log("download error source " + error.source);
console.log("download error target " + error.target);
console.log("upload error code" + error.code);
},
null, // or, pass false
{
//headers: {
// "Authorization": "Basic dGVzdHVzZXJuYW1lOnRlc3RwYXNzd29yZA=="
//}
}
);
}
function displayImageByFileURL(fileEntry) {
var elem = document.getElementById('imageElement');
elem.src = fileEntry.toURL();
}
I'm using the latest versions of the file-transfer and file plugins (1.7.1/6.0.1). I have added the domain to the Content-Security-Policy element as mentioned in the example:
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: http://cordova.apache.org https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
When I run it up in the simulator (Android/iOS) from VS2017 the download fails silently. Neither the success or error callbacks are called, and it doesn't appear to generate a network request. The console log is as follows:
file system open: http_localhost_4400:Temporary
Downloading http://cordova.apache.org/static/img/cordova_bot.png to filesystem:http://localhost:4400/temporary/downloaded-image.png
That filesystem URL looked a bit odd to me, so I have tried other variants such as the full file path, using persistent storage instead of temporary, using 'cdvfile://localhost/persistent/downloaded-image.png', all with the same result. I'm at a loss as to how I can debug this further and wondering if I've missed something really obvious, so any advice appreciated...
Edit
I tried running it again today, and a dialog pooped up in Visual Studio with the message:
There is no handler for the following exec call:
FileTransfer.download("http://cordova.apache.org/static/img/cordova_bot.png", "cdvfile://localhost/persistent/downloaded-image.png", true, 1, null)
I did some more experimenting, including running it up in the VS simulator for Android. For some reason it had trouble connecting to cordova.apache.org (I was also unable to access this site in the browser on the emulator), but downloading a file from github worked correctly....
I am currently trying to login to my app that is built on Ionic Framework using Venmo's Oauth API. I am attempting to use the Server Side Flow so that I can have a longer term access token. I am able to receive a code and set it to a requestToken variable.
However, when I attempt to post to "https://api.venmo.com/v1/oauth/access_token" with my Client Id, Client Secret, and Request Token, I get the following error alert: "ERROR: [object Object]".
In checking my console, I see that the error is a 400 Bad Request error coming on my post request, although it does appear that I have a valid request token. The error message is as follows: "Failed to load resource: the server responded with a status of 400 (Bad Request)".
Below is the code of the login function I am using to login via Venmo's Oauth API:
//VENMO SERVER SIDE API FUNCTION
var requestToken = "";
var accessToken = "";
var clientId = "CLIENT_ID_HERE";
var clientSecret = "CLIENT_SECRET_HERE";
$scope.login = function() {
var ref = window.open('https://api.venmo.com/v1/oauth/authorize?client_id=' + clientId + '&scope=make_payments%20access_profile%20access_friends&response_type=code');
ref.addEventListener('loadstart', function(event) {
if ((event.url).startsWith("http://localhost/callback")) {
requestToken = (event.url).split("?code=")[1];
console.log("Request Token = " + requestToken);
$http({
method: "post",
url: "https://api.venmo.com/v1/oauth/access_token",
data: "client_id=" + clientId + "&client_secret=" + clientSecret + "&code=" + requestToken
})
.success(function(data) {
accessToken = data.access_token;
$location.path("/make-bet");
})
.error(function(data, status) {
alert("ERROR: " + data);
});
ref.close();
}
});
}
if (typeof String.prototype.startsWith != 'function') {
String.prototype.startsWith = function(str) {
return this.indexOf(str) == 0;
};
}
This function is from this helpful walkthrough article by Nic Raboy (https://blog.nraboy.com/2014/07/using-oauth-2-0-service-ionicframework/). I think that the problem may be in how I am presenting the data array, so if anyone has any experience in successfully implementing a Venmo API in Ionic, your help would be much appreciated!
I was actually able to solve this issue with the method described above. In my original code, I omitted the line used to set the content type to URL encoded (which was included in Nic's example). Once I added this line, the request functioned as expected. The line was as follows:
$http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
I am trying to update the fixVersion of an issue via the JIRA rest api. The JIRA version is 4.4.3#663-r165197. It is the instance hosted by codehaus, not sure if that makes a difference or not.
The request looks like:
curl -u [username]:[password] -X PUT -H 'Content-type: application/json' \
-d "http://jira.codehaus.org/rest/api/latest/issue/GEOS-[id]"
{
"update":{
"fixVersions":[
{
"set":[
{
"name":"2.2-beta3"
}
]
}
]
}
}
But I get back a 405, method not allowed error. Which makes sense if I look at the rest api docs for that version [1]. They seem to indicate there is no way to update an issue in this manner. BUt if I look at the docs for the latest version [2] they seem to indicate it is possible.
So I guess the question is how do I update an issue in this manner in JIRA 4.4? Or is it not possible?
Thanks!
[1] https://developer.atlassian.com/static/rest/jira/4.4.1.html#id151460
[2] http://docs.atlassian.com/jira/REST/latest/#id165544
For 4.4 you have to use the SOAP updateIssue method. 5.0 fixed this.
Prepare Json data as below(Here java as technology i had used), and pass using put method/API.
public static String generateJson(String customFieldId, Object value,
String attribute) {
if (isBlankOrNull(attribute)) {
return "\"" + customFieldId + "\":" + "\"" + value + "\"";
} else {
return "\"" + customFieldId + "\":{\"" + attribute + "\":\"" + ""
+ value + "\"}";
}
}
public static int invokePutMethod(String auth, String url, String data) {
int statusCode = 0;
try {
Client client = Client.create();
WebResource webResource = client.resource(url);
ClientResponse response = webResource
.header("Authorization", "Basic " + auth)
.type("application/json").accept("application/json")
.put(ClientResponse.class, data);
statusCode = response.getStatus();
return statusCode;
} catch (Exception e) {
Constants.ERROR.info(Level.INFO, e);
// vjErrorLog.info(Level.INFO, e);
}
return statusCode;
}
attribute could be key, id, name, value etc,
In case of fix version or components, you may have one more way to prepare json data
return "\"" + customFieldId + "\":[{\"set\" :[{ \"" + attribute
+ "\" :" + "\"" + data + "\"}]}]";
and invoke put method with above json data.