Unauthorized request handling in Angular.js with Box API v2 - javascript

I am developing a web app with angular.js v1.5.7, which integrates Box Services using oauth2 authentication on the client-side to retrive the tokens for accessing the API.
I have a problem when the access token expires. I make a request with the expired token, and I receive a 401 (unauthorized) response that I can't catch in Angular because the response has a status code of -1. This happens before I am able to catch this response in a $httpsInterceptor.
I made a repository in GitHub to demonstrate this behavior https://github.com/danyfu/box-api-test, it's an express server that serves the 3000 port the Angular app.
In the Angular app, it's only a button you click to request to the API to GET the root folder of the user:
https://api.box.com/2.0/folders/0?fields=id,name,type,item_status,size,item_collection,shared_link
With the request I add the access token.
When I make the request with the invalid token, the response returns two error logs.
Errors
When I make the request with a valid access token, it retrieves the folder info and a status of 200.
Correct Information

You can use passport-box which will do the oauth flow in your app.
https://github.com/bluedge/passport-box
Here's an example where I use it as well:
https://github.com/kendomen/boxadmin

Related

UpdateToken() method does not refresh the access token

Need help with the below-faced issue in the implementation of Keycloak redirection in the flutter web application.
Flutter Package Used : keycloak_flutter | Flutter Package
The above package has used Keycloak JS adapter implementation. to achieve keycloak redirection in the flutter web application using the below reference.
Reference : Securing Applications and Services Guide
Describe the bug :
Using the package I am trying to refresh the access token by calling the update token method which makes the refreshtoken API request from keyclaok.js. but the request returns Status 400 Bad Request, then I checked the request in the browser tool(network tab), and the refresh_token is passed as undefined. I also tried to pass -1 as a parameter to the update token() which forcefully refresh the token.
access_token expires in 1 min
Expected behavior :
The update token method should refreshtoken if the access token is expiry.
Also Observed
Immediately after successfully login OnAuthLogout event is fired
the token expired event is not fired even after the token is expired
Thanks in Advance.

HTTP Basic Authentication in AngularJS

I am trying to call an API in AngularJS. API has HTTP Basic Authentication with username = admin and password = admin123
This is how I am calling the API,
$http.get('https://example.com', {
headers: {'Authorization': 'Basic YWRtaW46YWRtaW4xMjM='}
}).then(console.log("something"));
But, it is giving me 401 UnAuthorized response. What is the recommended way to pass the username and password ? I am using AngularJS 1.
Error is showing,
OPTIONS https://example.com 401 ()
Failed to load https://example.com: Response for preflight has invalid HTTP status code 401.
Possibly unhandled rejection: {"data":null,"status":-1,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","headers":{"Authorization":"Basic YWRtaW46YWRtaW4xMjM=","Accept":"application/json, text/plain, */*"},"url":"https://example.com"},"statusText":"","xhrStatus":"error"}
You're probably going to want to set the authorization headers at a more global level if all of your requests are going to need it. You can do this by adding
.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.headers.common['Authorization'] = '<Basic Auth Header>';
}]);
In your app config. To answer your actual question, I don't see anything specifically wrong with the code that you provided. Could you provide some information around what the server side is expecting and how it's reading the authorization?

LinkedIn OAuth redirect login returning "No 'Access-Control-Allow-Origin' header is present on the requested resource" error

I'm currently implementing OAuth login with LinkedIn in my React and Play app and am running into a CORS error when trying to redirect to the authorization page in my dev environment:
XMLHttpRequest cannot load https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_i…basicprofile&redirect_uri=http%3A%2F%2Flocalhost%3A9000%2Fusers%2Flinkedin. Redirect from 'https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_i…basicprofile&redirect_uri=http%3A%2F%2Flocalhost%3A9000%2Fusers%2Flinkedin' to 'https://www.linkedin.com/uas/login?session_redirect=%2Foauth%2Fv2%2Flogin-s…' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
I have the following setup:
Play server running at localhost:9000
React app (created via create-react-app) running at localhost:3000
My JS code calls the /auth/linkedin endpoint which is implemented as follows:
Action { implicit req: RequestHeader =>
val csrfToken = CSRF.getToken.get.value
Redirect(linkedinUrl(oauthConfig.linkedinClientId, csrfToken)).withSession("state" -> csrfToken)
}
I have my Play application set to handle CORS appropriately.
My react app just makes a request to the above endpoint via Axios:
axios.get('/auth/linkedin')
This responds with a 303 with a redirect to the LinkedIn auth page which then gives me the error.
How do I get the CORS policy working correctly in this dev setup? I've tried adding the following to my package.json as the create-react-app documentation recommends:
"proxy": "http://localhost:9000",
And I've also tried setting a request header to "Access-Control-Allow-Origin" : "*" on the redirect in the Play server with no success.
Note that going to localhost:9000/auth/linkedin redirects properly.
https://www.linkedin.com/oauth/v2/authorization responses apparently don’t include the Access-Control-Allow-Origin response header, and because they do not, your browser blocks your frontend JavaScript code from accessing the responses.
There are no changes you can make to your own frontend JavaScript code nor backend config settings that’ll allow your frontend JavaScript code to make requests the way you’re trying directly to https://www.linkedin.com/oauth/v2/authorization and get responses back.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS explains in more detail but the gist of it is: for CORS, the server the request is being sent to must be configured to send the Access-Control-Allow-Origin response header, nor your own backend server.
2019-05-30 update
The current state of things seems to be that when needing to do LinkedIn authorization, you’ll have to initiate the request from your backend code. There’s no way you can do it from your frontend code, because LinkedIn no longer provides any support for it at all.
LinkedIn did previously provide some support for handling it from frontend code. But the page that documented it, https://developer.linkedin.com/docs/getting-started-js-sdk, now has this:
The JavaScript SDK is not currently supported
And https://engineering.linkedin.com/blog/2018/12/developer-program-updates has this:
Our JavaScript and Mobile Software Development Kits (SDKs) will stop working. Developers will need to migrate to using OAuth 2.0 directly from their apps.
So the remainder of this answer (from 2017-06-13) has now become obsolete. But it’s preserved below for the sake of keeping the history complete.
2017-06-13 details, now obsoleted
Anyway https://developer.linkedin.com/docs/getting-started-js-sdk has official docs that explain how to request authorization for a user cross-origin, which appears to be just this:
<script type="text/javascript" src="//platform.linkedin.com/in.js">
api_key: [API_KEY]
onLoad: [ONLOAD]
authorize: [AUTHORIZE]
lang: [LANG_LOCALE]
IN.User.authorize(callbackFunction, callbackScope);
</script>
And https://developer.linkedin.com/docs/signin-with-linkedin has docs for another auth flow:
<script type="in/Login"></script> <!-- Create the "Sign In with LinkedIn" button-->
<!-- Handle async authentication & retrieve basic member data -->
<script type="text/javascript">
// Setup an event listener to make an API call once auth is complete
function onLinkedInLoad() {
IN.Event.on(IN, "auth", getProfileData);
}
// Handle the successful return from the API call
function onSuccess(data) {
console.log(data);
}
// Handle an error response from the API call
function onError(error) {
console.log(error);
}
// Use the API call wrapper to request the member's basic profile data
function getProfileData() {
IN.API.Raw("/people/~").result(onSuccess).error(onError);
}
</script>
I ran into a similar problem, so let's divide this problem into detailed steps
Hit request to get the code(from frontend)
now send this code to the backend
In the backend, make another call to LinkedIn OAuth API and get the access token
With this access token make 3 separate calls to get the name, profile picture
and email of the user(yes you heard that right you need to make 3 separate calls and also the response JSON format is not very appealing)
Visit this for the detailed step-by-step process, it involves a lot of things. I can just share the process here but for the actual implementation visit this.
https://www.wellhow.online/2021/04/setting-up-linkedin-oauth-and-fixing.html
What could be done is:
window.location.href='http://localhost:9000/auth/linkedin'
The urlEndPoint could be directly to linkedIn's API or a back-end service which makes the call to linkedIn's API.

Ember JS with remote auth backend (XML response)

Using Ember-Simple-Auth (custom authenticator) and Ember.$.ajax()
Authentication procedure:
Link to authsite.com/login, and log in there
If OK, external website redirects to mysite.com/someroute?sid=xxx&uid=xxx
I retrieve those parameters
I can get a big XML file with a lot of info by making a request to authsite.com/check?sid=xxx&uid=xxx if user is authenticated. Auth backend constraint: this request must come from the same IP as step 2.
I have a problem making this request because:
Not allowed by Access-Control-Allow-Origin
Not JSONP
Cannot enable CORS
Setting crossDomain: true and xhr credentials to true doesn't work either when doing Ember.$.ajax()
What are my options if I want to do everything in the front-end?

What should be the response code when error is generated by third party application?

I built a web application that basically ask the user for credentials with a form (for a random 3rd party service, knowing which one does not matter).
Once the user filled the form with the 3rd party service app token, a request with the token is sent to the application backend, the backend gets the token and send a request to the 3rd party service in order to check if the token is valid.
At this point the 3rd party service returns a response to the backend with either 200 - {randomObject: object} or 401 - Unauthorized.
So here is my question : If the 3rd party service returns 401, should the backend returns 200 - false or 401 - Unauthorized ?
Me and my colleague have been arguing about this.
My point is that the access to the application backend is authorized and the parameters are correct (a token is present in the request), so the response should be 200 but the content of the response should indicate wether or not the token is valid.
His point is that since the token is not valid (as the 3rd party service tells the backend), the backend should return 401 - Unauthorized.
Just so we're clear, I know that the outcome is in both cases the same, as a matter of fact this functionality already works, I just want to know is there are some sort of convention regarding this specific matter.
Thank you
I would go for either 400 or 401.
401 might be misleading because access to your API was not unauthorized. (especially if your api also requires authentication)
on the other hand 400 might be best :
The 400 (Bad Request) status code indicates that the server cannot or
will not process the request due to something that is perceived to be
a client error
I would say it should be a 401 still. The workings of your backend should have no bearing on the application in the sense that its inner workings aren't important to the end user. The fact that your auth service is telling you it isn't valid should be enough for you to throw this error.
On this:
My point is that the access to the application backend is authorized
and the parameters are correct (a token is present in the request), so
the response should be 200
The presence of a token does not mean that the request is valid. 401 Unauthorized should be used, since invalid credentials were provided. From httpstatuses.com:
The request has not been applied because it lacks valid authentication
credentials for the target resource.
If you were thinking it should be a 200 because the credential is not for your service, but for a third-party service and so authorization to your service is not failing, that could be argued, but in that case you still probably don't want to return a 200 but instead a 400 Bad Request since the parameters to successfully complete the API operation are invalid.
I'll buck the trend a bit and say you should return 200.
The status code 401 is related to HTTP authentication. W3C has the following to say on the status code:
The request requires user authentication. The response MUST include a
WWW-Authenticate header field (section 14.47) containing a challenge
applicable to the requested resource. The client MAY repeat the
request with a suitable Authorization header field (section 14.8). If
the request already included Authorization credentials, then the 401
response indicates that authorization has been refused for those
credentials. If the 401 response contains the same challenge as the
prior response, and the user agent has already attempted
authentication at least once, then the user SHOULD be presented the
entity that was given in the response, since that entity might include
relevant diagnostic information.
(source)
Since your server presumably does not use HTTP authentication itself, you won't be returning a WWW-Authenticate header with a challenge, hence you won't be following this spec correctly. The 3rd party API you are calling may do this correctly, but that is by the by. Your user has requested a page from you, not the third party API directly, and they are authorised to do that. Your server has not decided that they are not worthy of a valid response - someone else's server has just told you that their token is not valid.
Given this, I would return a 200. The request has succeeded. Your server is able to return information indicating that the third party API call failed.

Categories