I have a service stack web service with the CorsFeature enabled.
I am calling a service through AngularJS's $http.get method with the setting withCredentials to true:
$http.get(url,{ withCredentials: true})
How do I securely pass the credentials to be used by the rest api?
On the ServiceStack side you must set your CorsFeature plugin to have allowCredentials = true and set a single origin. You can't have an origin of * when using allowCredentials.
withCredentials basically allows your origin domain and the ServiceStack service endpoint to share cookies, and pass the Authorization HTTP header, (when CORS is correctly configured). So ultimately your credentials could be a session cookie or an Authorization HTTP header.
This Mozilla documentation about CORS is good at explaining how the cross domain withCredentials works.
Because the CORS feature and withCredentials only sets up the ability for the domains to share cookies and pass the Authorization header, and doesn't do the authentication - you will need to find a suitable authentication mechanism.
You can either build your own authentication mechanism, or consider implementing the ServiceStack Authentication provider, which you can read about it here. Essentially you would want to do a post to:
POST server:port/auth/credentials?format=json
{
"UserName": "admin",
"Password": "test"
"RememberMe": true
}
The authentication service would pass back a session cookie, and when you use withCredentials in your later requests, the cookie will be included automatically, and thus your request will authenticate.
To address passing the credentials securely, you will want to use HTTPS to avoid exposing the credentials in transit. This means securing the username and password value, as well as the session token value.
Hope this helps.
Related
Question is linked to Azure AD Easy Auth expires even when users are actively using application. Based on explanation shared it seems Easy Auth mechanism is not the right fit for SPA hosted on Azure Web Apps?
Can MS add mentioned options under official documentation -
"https://learn.microsoft.com/en-in/azure/app-service/app-service-authentication-overview?toc=%2fazure%2fapp-service-web%2ftoc.json"
I am facing the following issue:
when AppServiceAuthSession cookie expires, any SPA AJAX requests to underlying secure API Calls fails with CORS issue :Failed to load https://login.windows.net//oauth2/authorize?response_type=code+id_token&redirect_uri=https%3A%2F%2Fapp.contoso.com%2F.auth%2Flogin%2Faad%2Fcallback&client_id=xxxxx&scope=openid+profile+email&response_mode=form_post&nonce=xxxxx&state=redir%3D%252Fapi%252Fv2%252Fget-dataapi: Redirect from 'https://login.windows.net/xxxxxxxxxxxx/oauth2/authorize?response_type=code+id_token&redirect_uri=https%3A%2F%app.contoso.com%2F.auth%2Flogin%2Faad%2Fcallback&client_id=xxxxx&scope=openid+profile+email&response_mode=form_post&nonce=xxxx&state=redir%3D%252Fapi%252Fv2%252Fget-dataapi' to 'https://login.microsoftonline.com/xxxxxxxxxx/oauth2/authorize?response_type=code+id_token&redirect_uri=https%3A%2F%app.contoso.com%2F.auth%2Flogin%2Faad%2Fcallback&client_id=xxxxxxxxxx&scope=openid+profile+email&response_mode=form_post&nonce=xxxxxxxxxxx&state=redir%3D%252Fapi%252Fv2%252Fget-dataapi' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://app.contoso.com' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I am facing the following issue: when AppServiceAuthSession cookie expires, any SPA AJAX requests to underlying secure API Calls fails with CORS issue
Per my understanding, you are using the build-in App Service Authentication / Authorization (EasyAuth) feature with your SPA without writing any code or using client library for authentication in your SPA.
For Ajax request with the invalid cookie or token, I could encounter the similar issue as follows:
At this time, you could capture the Ajax error and redirect your SPA for re-authenticate to retrieve the new AppServiceAuthSession cookie.
Chris Gillum's answer in
Azure AD Easy Auth expires even when users are actively using application
could fit your scenario.
Based on my experience, you could use the JavaScript client library for Azure Mobile Apps in your SPA for retrieving the x-zumo-auth token and use the token approach as Chris Gillum answered. For a simple way, you could use the server-flow authentication as follows:
client.login("aad").done(function (results) {
alert("You are now logged in as: " + results.userId);
console.log("x-zumo-auth token is: "+ results.mobileServiceAuthenticationToken);
}, function (err) {
alert("Error: " + err);
});
Also, you could directly retrieving the AAD id_token or access_token via using Active Directory Authentication Library (ADAL) for JavaScript as juunas commented, then include the token (id_token, access_token) in the Authorization header as a bearer token to request your WebAPIs.
Additionally, you could use the client-flow authentication for App Service, and retrieve the id_token or access_token via ADAL.js, then use the previous token to login with EasyAuth for retrieving the AuthenticationToken as the x-zumo-token, then use the x-zumo-token to request your WebAPIs.
we plan to introduce an API management solution and we're currently setting up a proof of concept with WSO2 AM. We want to use the WSO2 API gateway to check whether a certain consumer application is allowed to use an API and to throttle the request rate.
I work on the identity workflow and I wonder how a consuming application can pass a JWT token to the backend service with WSO2-AM in between.
First, this is our current scenario:
Without API gateway
The consuming application gets a JWT token for its carbon user from an identity provider. The JWT contains some claims about the user, e.g. the roles he/she belongs to.
The app calls the service an passes the JWT token in the Authorization HTTP header like: Authorization: Bearer
The service validates the issuer and signature of the JWT and retrieves the claims from it.
So, this is pretty straight forward. Now we put an API gateway in between the application and the service:
With API gateway
The consuming application gets a JWT token for its carbon user from an identity provider.
The consuming application uses OAuth2 to get an access token for the following API calls. We can use the client_credentials grant type and simply pass the the client id and client secret. I haven't yet tried it, but we could possibly use the JWT grant type (see https://docs.wso2.com/display/ISCONNECTORS/Configuring+JWT+Grant+Type) and use the JWT for passing user information to the API gateway.
The API gateway validates the JWT against the public key of the identity provider when using the JWT grant type.
An access token is returned to the app.
The app sends an API request to the gateway and passes the access token in the Authorization HTTP header.
The gateway validates the access token.
The gateway forwards the API request to the service.
And there is my problem: How can the JWT from 1/2. be passed to the service?
There is a documentation for "Passing Enduser Attributes to the Backend Using JWT" (see https://docs.wso2.com/display/AM210/Passing+Enduser+Attributes+to+the+Backend+Using+JWT), but this would introduce a new JWT, issued and signed by WSO2-AM, and I'm not sure, whether this JWT contains all information from the JWT used to create the access token (or even the original JWT).
Another way I could think of is using a custom HTTP header for passing the JWT through the gateway to the service. I cannot use the Authorization header (as we do without the API gateway), because WSO2-AM expects the access token in that header.
Since I'm not happy with either solutions, I want to ask the experts: How would you solve this?
Thanks,
Torsten
The only possibility I can think of is to send the JWT token in a custom Header for the backend service.
We are implementing a sample application using Kong API gateway with JWT authentication plugin.
As refer in this thread, there are two ways to store JWT in the browser. Web storage or cookies. But web storage (i.e. session storage and local storage) can be vulnerable to cross-site scripting attack(XSS). So other option is cookie. (Though CSRF should be taken care off)
I have two questions,
If we use web storage to store JWT then is there any way to stop XSS. If yes then how it will work if the same page is open in the new tab or reload the same page ?
Using cookie: We are able to send the cookies in the request. But KONG is authenticating the end point URL only if the JWT is set on headers (Authorisation: Bearer token) and not authenticating using cookies. Is there any way to verify JWT which is set in cookies using KONG API Gateway ?
There is nothing wrong about storing JWT in webStorage, unless you store sensitive data in your JWT (but you should never ever do that, since you can decode it easily). The point is that your token shares a secret, that only your servers knows (that's what makes it secure), you should just put an expiration time to make it a lot safer.
And no, you cannot pass a JWT token in cookies, it's only in headers (here Authorization), I don't know about KONG API, but they should not allow that !
(ref about JWT is here)
In order to add to #antoine2vey answer,
It looks like your on page application is being served from a protected API in Kong at the "/" (slash) resource. I would suggest that you would be able to get the page content from an unprotected "/" (slash) resource and then run javascript code would have access to the cookie and would be able to perform the request to the protected resource passing the JWT token in the header where Kong would be able to validate for you.
Does this make sense?
Cookie based authentication is implemented. https://github.com/Kong/kong/pull/2973
Starting with the following repo at https://github.com/mjrousos/IdentityServer4Authentication, I added a "ValuesController" with a single "Get" method with the [Authorize] attribute. When I login using the web front end I'm able to access this endpoint just fine - the web bits contain the standard web bits found in the IS4 Quickstarts.
However, when I request a token from the token endpoint (/connect/token) with the following body (raw) "grant_type=password&username=gvdonovan%40gmail.com&password=Pass20!7&client_id=myClient&scope=myAPIs" and then use this token in a Get request with a single Authorization header with a value of "bearer [my token]" I receive a 401 Unauthorized response.
You've got your Identity Server and your 'protected controllers' in the same project, with a single startup, which is a configuration I'm not used to.
For our use of IdSvr, we made sure that the startup for the client (a web api) used the middleware "UseIdentityServerAuthentication" in the configure method, with appropriate definitions for what the acceptable Authority and AllowedScopes are for that client.
Then the use of the Authorize header on protected API resources will auto-magically call the authority (our IdSvr) to verify the token.
Our IdSvr doesn't have controllers or "app.UseMvc", because it is just for issuing/verifying tokens.
I'm building an Angular app with an API backend. On a combination of pieces of advice, I built the API with a flavor of token authentication. The flow is roughly as follows:
POST to login endpoint with credentials
Validate credentials and authorization, then generate a new token
Return token to client
Client uses token via HTTP Basic to access API resources
This is all working well. The problem arises in creating a session based on this token. I don't believe I should simply hold the token on the client in a cookie, but I do need a session to persist between page refreshes, etc. My Angular app is stateless and completely populated via API calls.
I'm looking for a recommendation as to hanging on to this token on the client. I feel there's danger in holding the token in a cookie because the cookie could be stolen and simply used to authenticate as someone else, but perhaps this is incorrect.
Thanks in advance for your assistance!
The only known way for me to identify a user is to use some token on the client.
HTTP is stateless and can't know which request is coming from which user (browser). You can't identify the user by his ip address (many users are behind a router and share a connection). You could try browser fingerprinting, it can work on some browsers but not on all.
I would recommend using a cookie to store this token on the client.
They are send to the server on every request and you can do some protection to keep them from getting stolen.
To protect this cookie from man in the middle attacks you need to use an encrypted connection over HTTPS to the server.
Set the following attributes on the cookie:
HTTPOnly: cookie can't be accessed by javascript (XSS protection)
Secure: cookie will only be send over https
Path: cookie will only be send on specified path e.g. /login
I would also define an expiration date on the cookie, so the cookie is invalid in like 2 days or something.
But you are right. If this token gets stolen someone else can login as this user.
Since its an Angular app, I'd assume all authenticated methods will only be served to ajax requests (you can tell your server to only respond to ajax) in which case CORS will help you.
The only way to be completely secure is HTTPS, however this method is probably more secure than you think. Read up on CORS a bit for more info, but essentially the idea is that servers will only respond to ajax requests coming from html pages that were served by that same domain.
Pre-flight OPTIONS requests are often sent to verify this. The browser sends an OPTIONS request with an Origin header (the origin of the page) before the actual request. If the origin matches the domain of the server receiving it, the subsequent request is allowed. Otherwise, it violates the Same Origin Policy and will be rejected.
This prevents someone from sniffing out the token and sending a request with the token from a page that your server didn't serve (like something running on the hackers local machine).
If you are doing credit card transactions or anything super secure, you should use HTTPS though.
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing