Handle 401 error

Hi, I try to used a JSON API back-end secured by keycloak. This back-end reponse with a 401 www-autenticate.

The problem is that i’m unable to retrieve the status code of the error. I’ve tried to overwrite the adapter.handleResponse(). But this does not work. The application route error object does not contains the status code. Any idea how to handle this case?

Hi @scandinave! I’ve used the error hook in the route to handle such things. See the docs for more information, but what I’ve done for this & other types of errors:

handleResponse in app/adapters/application.js:

export const UnauthenticatedError = AdapterError.extend({message: 'Unauthenticated'});

...

handleResponse(status, headers, _payload, requestData) {
  if(status === 401) { return new UnauthenticatedError() }
  /* other cases here */

  return super(...arguments);
}

and then in app/routes/application.js:

import { UnathenticatedError } from '../adapters/application';

...

actions: {
  error() {
    if(error instanceOf UnauthenticatedError) {
      this.transitionTo('login');
    } else if (/* other cases */) ....
  }
}}

Hi,

I am also trying to react to 401 status codes. I can not find any working example. Is there another way I can globally catch 401 or any bad status code errors in octane? What I did is adding the following to app/routes/application.js:

  error(error, transition) {
  return this.transitionTo('login');
  }

So I do not even care what error we have, it shall simply forward to login. But I am receiving "Uncaught (in promise) " in my webconsole.

Maybe all this examples are not compatible with octane? Any hints would be appreciated.

@Dantel do you have any other details about the error being thrown?

Hi dknutsen,

thank you for having a look. This is what I can dig up:

DEBUG: ------------------------------- index.js:192
DEBUG: Ember             : 3.24.1 index.js:192
DEBUG: Ember Data        : 3.24.0 index.js:192
DEBUG: Ember Simple Auth : 3.1.0 index.js:192
DEBUG: ------------------------------- index.js:192

Uncaught (in promise) 
{…}
​
description: undefined
​
errors: (1) […]
​​
0: Object { status: "401", title: "The backend responded with an error", detail: "[object Object]" }
​​
length: 1
​​
<prototype>: Array []
​
fileName: "http://localhost:4200/assets/vendor.js"
​
isAdapterError: true
​
lineNumber: 67528
​
message: "Ember Data Request GET /api/accounts/checksession returned a 401\nPayload (application/json;charset=UTF-8)\n[object Object]"
​
name: "Error"
​
number: undefined
​
stack: "AdapterError@http://localhost:4200/assets/vendor.js:67528:29\nErrorClass@http://localhost:4200/assets/vendor.js:67561:24\nhandleResponse@http://localhost:4200/assets/vendor.js:69446:18\najaxError@http://localhost:4200/assets/vendor.js:69777:25\nfetchErrorHandler@http://localhost:4200/assets/vendor.js:69830:12\najax/<@http://localhost:4200/assets/vendor.js:69536:19\ninvokeCallback@http://localhost:4200/assets/vendor.js:63745:17\npublish@http://localhost:4200/assets/vendor.js:63728:23\n@http://localhost:4200/assets/vendor.js:58104:61\ninvoke@http://localhost:4200/assets/vendor.js:56307:16\nflush@http://localhost:4200/assets/vendor.js:56198:19\nflush@http://localhost:4200/assets/vendor.js:56395:21\n_end@http://localhost:4200/assets/vendor.js:56929:34\nBackburner/this._boundAutorunEnd@http://localhost:4200/assets/vendor.js:56598:14\n"
​
<prototype>: {…}
​​
code: "UnauthorizedError"
​​
stack: ""
​​
<prototype>: {…}
​​​
code: "AdapterError"
​​​
stack: ""
​​​
<prototype>: Error.prototype
​​​​
constructor: function Error()
​​​​
message: ""
​​​​
name: "Error"
​​​​
stack: ""
​​​​
toString: function toString()
​​​​
<get stack()>: function stack()
​​​​
<set stack()>: function stack()
​​​​
<prototype>: Object { … }

Now all I want to do is to catch this somewhere where I can execute my appropriate logic.

@Dantel the guides show an example of what you’re trying to do I think. However it looks like you should use the action decorator, and the example is also using replaceWith instead of transitionTo:

  @action
  error(error, transition) {
    this.replaceWith('login');
  }

IIRC this will only intercept errors encountered while transitioning (and only on the route you’re using this action on). So if you want to intercept errors more “globally” you may want to consider handling this at a different level in addition/instead. For example in Ember Simple Auth errors this logic is handled in the handleResponse method of the application adapter so (assuming you use Ember Data) any request made via Ember Data that receives a 401 response will redirect to login route.

EDIT: replaceWith is probably what you want to use but it really only affects history entries IIRC so probably not a big deal either way

1 Like

Hi dknutsen,

thanks a lot, this is really helpful! I actually did already try to override “handleResponse” in the application adapter, just like shull demonstrated above. But I can actually do something like this:

handleResponse(status, headers, _payload, requestData) {
  if(status === 401) {
   //do NOT return any error, instead handle it here
  }
  return super.handleResponse(status,headers,_payload,requestData);
}

Putting an alert in there triggered it every time, so this is nice. But now I am in the adapter and not in the route anymore. Is there any simple and clean way to call replaceWith/transitionTo outside of a route? So I could hook in my error handling in handleResponse and then transition from there.

You can inject the router service pretty much anywhere you need to, and use that to transition. So you could inject the router service into your application adapter and then use it in the handleResponse method, something like:

import { inject as service } from '@ember/service';
...
  @service router;
  ...
  handleResponse(status, headers, _payload, requestData) {
    if(status === 401) {
      this.router.transitionTo('login');
    }
    return super.handleResponse(status,headers,_payload,requestData);
  }
  ...

Ah nice, a router service. So I guess I’ll create an error_handling service which will handle the dirty work and hook it into handleResponse to keep the adapter clutter free.

Thank you very much!

1 Like