I am trying to set up authorization on an Ember App running on a Node.js server.
I am using the oauth2 Authenticator, which is requesting a token from the server. This is working fine. I am able to provide the app with a token, which it saves in the local-storage.
However, when I make subsequent requests, the authorizer is not adding the token to the header, I have initialized the authorizer using the method described in the documentation (http://ember-simple-auth.simplabs.com/ember-simple-auth-oauth2-api-docs.html):
Ember.Application.initializer({
name: 'authentication',
initialize: function(container, application) {
Ember.SimpleAuth.setup(container, application, {
authorizerFactory: 'authorizer:oauth2-bearer'
});
}
});
var App = Ember.Application.create();
And I have added an init method to the Authorizer, to log a message to the server when it is initialized, so I know that it is being loaded. The only thing is, the authorize method of the authorizer is never called.
It feels like I am missing a fundamental concept of the library.
I have a users route which I have protected using the AuthenticatedRouteMixin like so:
App.UsersRoute = Ember.Route.extend(Ember.SimpleAuth.AuthenticatedRouteMixin, {
model: function() {
return this.get('store').find('user');
}
});
Which is fetching the data, fine, and redirects to /login if no token is in the session, but the request headers do not include the token:
GET /users HTTP/1.1
Host: *****
Connection: keep-alive
Cache-Control: no-cache
Pragma: no-cache
Accept: application/json, text/javascript, */*; q=0.01
Origin: *****
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36
Referer: *****
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Any help you could give me would be greatly appreciated.
Is your REST API served on a different origin than the app is loaded from maybe? Ember.SimpleAuth does not authorizer cross origin requests by default (see here: https://github.com/simplabs/ember-simple-auth#cross-origin-authorization)
Related
I'm trying to made a POST request on a NET CORE 5 service (hosted on IIS 10) from a Vue.js app with axios.
When I test the service with POSTMAN it's working perfectly but with Axios I'm always getting a 405 from the server.
Analyzing the requests with fiddler are looking very different. IN the axios request the content-type header is missing and the method is OPTIONS instead of POST.
This is the POSTMAN request:
POST https://localhost/apiluxor/api/SignIn HTTP/1.1
Content-Type: application/json
User-Agent: PostmanRuntime/7.28.4
Accept: */*
Postman-Token: acfed43c-731b-437b-a88a-e640e8216032
Host: localhost
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 55
{
"username":"user",
"password":"testpw"
}
And this is the axios request:
OPTIONS https://localhost/apiluxor/api/SignIn HTTP/1.1
Host: localhost
Connection: keep-alive
Accept: */*
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://172.16.1.110:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Sec-Fetch-Dest: empty
Referer: http://172.16.1.110:8080/
Accept-Encoding: gzip, deflate, br
Accept-Language: it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7
In my Vue.js module I've tried to force the settings of the 'content-type' in the main config and in the post request with no results.
import { App } from "vue";
import axios from "axios";
import VueAxios from "vue-axios";
import JwtService from "#/core/services/JwtService";
import { AxiosResponse, AxiosRequestConfig } from "axios";
class ApiService {
public static vueInstance: App;
public static init(app: App<Element>) {
ApiService.vueInstance = app;
ApiService.vueInstance.use(VueAxios, axios);
ApiService.vueInstance.axios.defaults.baseURL =
"https://localhost/apiluxor/api";
ApiService.vueInstance.axios.defaults.headers.post["Content-Type"] =
"application/json";
}
public static setHeader(): void {
ApiService.vueInstance.axios.defaults.headers.common[
"Authorization"
] = `Bearer ${JwtService.getToken()}`;
}
public static post(
resource: string,
params: AxiosRequestConfig
): Promise<AxiosResponse> {
return ApiService.vueInstance.axios.post(resource, params, {
headers: { "content-type": "application/json" },
});
}
export default ApiService;
I'm very new to Vue.js so maybe I'm missing something.
The problem is that axios made a CORS request before the POST, and the NET Core API should be configured to accept CORS request.
I've found an article (here) that saying the problem for this cases is that IIS does not accept CORS request and the CORS module should be installed .
I've tried this change but the result was the I was receving an HTTP/1.1 204 No Content instead of a 403.
In my case the problem was the API service itself.
The CORS should be enabled in the API Service.
In NET CORE 5 for a basic configuration it's enough to add the CORS services in Startup
services.AddCors();
and configure it
app.UseCors(builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
With these changes the service works perfectly for any vue.js requests coming from axios.
To send the data as JSON in the body of the post request, just add a parameter "data" to the axios options. Axios will automatically set the content-tpe to the proper value for you.
// Simple example
axios.post(myUrl, {
data: {
"username":"user",
"password":"testpw"
}
});
This should have the expected outcome :)
Is there something different that needs to be done when uploading a file? Every other call (Axios/Vue put) works fine except where a file is getting uploaded. It's going from example.com to api.example.com. Everything works fine locally hitting different ports.
ConfigureServices:
services.AddCors(o => o.AddPolicy("CorsPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowedToAllowWildcardSubdomains();
//.WithOrigins("http://*.example.com"); //tried adding, nothing works when it's here
}));
Configure:
app.UseCors("CorsPolicy");
And the controller:
[ApiController]
[EnableCors("CorsPolicy")]
public class MyController : ControllerBase {
Public Model Put([FromForm] ICollection<IFormFile> files, [FromForm] string jsonString)
The browser output:
Access to XMLHttpRequest at 'http://api.example.com/api/YourKnowledge' from origin 'http://example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Request URL: http://api.example.com/api/YourKnowledge
Referrer Policy: strict-origin-when-cross-origin
Date: Sat, 03 Oct 2020 19:58:42 GMT
Server: Microsoft-IIS/10.0
Transfer-Encoding: chunked
X-Powered-By: ASP.NET
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 10219
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryvIG7idij6Og7BH8r
Host: api.example.com
Origin: http://example.com
Referer: http://example.com/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36
files: (binary)
jsonString:{}
Last note, I did find this Asp.Net Core API CORS policy error only in file upload, but I won't have just images uploaded. Did try setting it to test, but it didn't make a difference.
I think you couldn't add two parameter with [FromForm]
(I know that its the rule at least in [FromBody]).
please let me know that works
I tried making a get call with axios from my Vue js codebase/ environment to Jenkins API and I'm unable to do so.
I've read every resource that I could but wasn't able to fix this particular problem. I even created a .htaccess file to see if it help but wasn't useful.I ran out of options so I came here for help.
Below are the axios codes that I used within my App.vue file.
axios.get(
*URL to access Jenkins that is currently running on a tomcat server*,
{
headers: {
"jenkins-crumb": "* Some numbers and letters*",
},
auth: {
username: "*obvious username*",
password: "*obvious password*"
},
withCredentials: true,
crossdomain: true
}
)
.then(response => (this.info= response)).catch(error => (console.log(error)));
Console log output:
Access to XMLHttpRequest at 'url' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Network output:
General
Request URL: URL
Request Method: OPTIONS
Status Code: 403
Remote Address: localhost:8080
Referrer Policy: no-referrer-when-downgrade
Request Headers
Provisional headers are shown
Access-Control-Request-Headers: authorization,jenkins-crumb
Access-Control-Request-Method: GET
Origin: http://localhost:8080
Referer: http://localhost:8080/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
Please help!
I'm building an Outlook add-in with jQuery and the Office JS API. I have a local server going while developing, and I'm trying to submit a POST request to an endpoint on my site's main server. Every time I try to submit the request, I get the following three errors:
Origin https://localhost:3000 is not allowed by Access-Control-Allow-Origin
XMLHttpRequest cannot load https://myurl.com/my_endpoint due to access control checks
Failed to load resource: Origin https://localhost:3000 is not allowed by Access-Control-Allow-Origin
What I've done so far:
Found this related thread: HTTP fetch from within Outlook add-ins
The only answer says to do three things:
Make the request with XMLHttpRequest. Yup, did that:
function submitForm(var1, var2) {
var http = new XMLHttpRequest();
var params = 'var1=' + encodeURIComponent(var1) + '&var2=' + encodeURIComponent(var2);
http.open("POST", 'https://myurl.com/my_endpoint', true);
http.setRequestHeader('Access-Control-Allow-Origin', 'https://localhost:3000');
http.setRequestHeader('Access-Control-Allow-Credentials', true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.onreadystatechange = function() {
console.log("response:", http.responseText);
console.log("status:", http.status);
};
http.send(params);
}
Add the service URL into the manifest's AppDomains list. Yup, did that, too. This is from my manifest.xml:
<AppDomains>
<AppDomain>https://myurl.com</AppDomain>
<AppDomain>https://myurl.com/my_endpoint</AppDomain>
<AppDomain>https://localhost:3000</AppDomain>
</AppDomains>
Use only services which are under SSL connection. Yup, the myurl.com server is only accessible via SSL.
I also found this documentation (https://learn.microsoft.com/en-us/office/dev/add-ins/develop/addressing-same-origin-policy-limitations) that recommends to solve this with cross-origin-resource-sharing (CORS), and points to this link: https://www.html5rocks.com/en/tutorials/file/xhr2/#toc-cors
So, I checked the server set-up for https://myurl.com and I am in fact allowing requests from any origin. UPDATE 1: as an example, here's what the output of a successful network request to https://myurl.com/my_endpoint looks like (notice the Accept: */* header):
Request URL: https://myurl.com/my_endpoint
Request Method: POST
Status Code: 200 OK
Referrer Policy: no-referrer-when-downgrade
Cache-Control: no-cache, no-store, must-revalidate, public, max-age=0
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/html; charset=utf-8
Expires: 0
Pragma: no-cache
Server: nginx/1.10.3 (Ubuntu)
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 52
Content-type: application/x-www-form-urlencoded
Host: myurl.com
Origin: chrome-extension://focmnenmjhckllnenffcchbjdfpkbpie
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
var1: var1
var2: var2
Plus, another thing leading me to believe the problem isn't with https://myurl.com is: when I open my network tab in my debugger, I can see that my request never reaches https://myurl.com. I'm also not seeing the request pings in my https://myurl.com server logs. This is the output of my network request when I try to ping https://myurl.com from the Outlook add-in:
Summary
URL: https://myurl.com/my_endpoint
Status: —
Source: —
Request
Access-Control-Allow-Origin: https://localhost:3000
Access-Control-Allow-Credentials: true
Content-Type: application/x-www-form-urlencoded
Origin: https://localhost:3000
Accept: */*
Referer: https://localhost:3000/index.html?_host_Info=Outlook$Mac$16.02$en-US
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14) AppleWebKit/605.1.15 (KHTML, like Gecko)
Response
No response headers
Request Data
MIME Type: application/x-www-form-urlencoded
var1: var1
var2: var2
Any recommendations for what else I need to change to enable making a POST request to myurl.com? Thanks in advance to the kind soul that helps me figure this out.
UPDATE 2: For what it's worth, I haven't done any configs to my node server beyond what came out-of-the box when I ran npm install -g generator-office. E.g. I haven't touched these two files:
.babelrc
{
"presets": [
"env"
]
}
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
polyfill: 'babel-polyfill',
app: './src/index.js',
'function-file': './function-file/function-file.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.html$/,
exclude: /node_modules/,
use: 'html-loader'
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: 'file-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
chunks: ['polyfill', 'app']
}),
new HtmlWebpackPlugin({
template: './function-file/function-file.html',
filename: 'function-file/function-file.html',
chunks: ['function-file']
})
]
};
Failed to load resource: Origin https://localhost:3000 is not allowed by Access-Control-Allow-Origin
The server responds to your pre-flight request (usually OPTIONS) and does not allow to get a response, that's because your origin localhost:3000 is not allowed on server side.
You need to respond to OPTIONS on server with 204 status code and a header like:
Access-Control-Allow-Origin 'localhost';
WEbAPI provides end-point for authentication request: http:\...\token
Authentication request should be sent using Method "POST" and Body like
"grant_type=password&username=name&password=mypassword"
This WebAPI is used by Front-End which is written using AngularJS.
Sometimes before sending "POST" request with valid Body, a "OPTIONS" request is sent without Body.
As result the following error is returned by WebAPI:
Status: 400
{"error":"unsupported_grant_type"}
Is there any solution which can be implemented on Server-side? (in WebAPI)
HTTP Request Method: OPTIONS
Request Header:
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,de;q=0.6,ru;q=0.4,uk;q=0.2
Access-Control-Request-Headers:accept, authorization, content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Host:...
Origin:...
Pragma:no-cache
Proxy-Connection:keep-alive
Referer:...
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36
Response Header:
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/7.5
Access-Control-Allow-Origin: *
X-Powered-By: ASP.NET
Date: Thu, 11 Sep 2014 18:05:09 GMT
I just ran into the same issue..I'm using ember and ember-simple-auth. Any preflight requests OPTIONS to the /token endpoint were resulting in a 400 HTTP response and the body had the well known: {error: "unsuported_grant_type"}.
SOLUTION:
I inherit from: OAuthAuthorizationServerProvider and override the MatchEndpoint function:
public override Task MatchEndpoint(OAuthMatchEndpointContext context)
{
if (context.OwinContext.Request.Method == "OPTIONS" && context.IsTokenEndpoint)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Methods", new[] {"POST"});
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "accept", "authorization", "content-type" });
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
context.OwinContext.Response.StatusCode = 200;
context.RequestCompleted();
return Task.FromResult<object>(null);
}
return base.MatchEndpoint(context); }
That seems to take care of it. Hope it helps.
I got the same error when I forgot to add Content-Type: application/x-www-form-urlencoded to the request header.
I was attempting to test my api with Fiddler and wasn't providing the data in the correct format in the Request Body section. Be sure it's added as a key value list separated by '&'.
grant_type=password&username=testUsername&password=testPassword
In this case OPTIONS is a CORS preflight request. It is sent in order to determine whether the actual request (POST) is safe to send. Cross-site requests are preflighted if uses methods other than GET, HEAD or POST or sets custom headers.
In order to avoid a 400 HTTP response, in your Startup class you should enable CORS for the OWIN middleware using UseCors extension method and define your custom System.Web.Cors.CorsPolicy.
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security.OAuth;
using Owin;
namespace AuthorizationServer
{
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions()
{
});
}
}
}