Loopback-next: Required to annotate with @authenticate for all the routes!

Created on 23 Feb 2019  路  13Comments  路  Source: strongloop/loopback-next

Current Behavior

I have to annotate all of my controller routes with @authenticate('startegry_name'), but in my case I just have a single strategy and don't like the compulsion of adding the @autheticate annotation to each of my 20-30 routes. Though, one or two routes are there where I don't need any authentication and should be available for public.

Expected Behavior

Would be better if there is a way to have authentication default for all routes except for one or two. IF there is already some sort of way available please let me know what would be that.

Acceptance criteria

  • [ ] if a method is decorated with @authenticate, the method would use the metadata as is without checking the class
  • [ ] if a method is not decorated with @authenticate, the method would check the class level
  • [ ] introduce @authenticate.skip or @authenticate('skip') to exclude a method to inherit @authenticate from the class
  • [ ] update relevant docs in the site
2019Q4 Authentication developer-experience feature

All 13 comments

except for one or two.

A whitelist effectively? I do think that is a nice to have(if not already). Low priority.

So, is it nice to have all paths which may go up to any number (in my case around 30) and all to be annotated with @authenticate !?. How about the case when there is just one strategy and all the paths (ignore my mention about one or two paths and assume all paths) needs to be authenticated with that strategy

Also, is it good way - for example if for some reason, if someone forget to annotate, than that path will be public.

Unless I missed something, I feel I am asking a very simple question about a common scenario that many will be facing.

@vishalvisd I also discussed with team about having a controller class decorator that sets one authentication strategy for all the methods. Will update the progress here when we start, now as a workaround, you can hardcode what strategy to return in the strategy resolver, see this example.

In the example above, the strategy resolver returns the strategy according to a controller function's metadata, in your case you can just ignore the metadata and return the particular strategy you want.

I know about this, but this need to still annotate all routes which I think is not a workaround.

Thanks for taking it up for discussion, hope to see an update on this soon. Loopback is a great framework and I really appreciate the effort you guys are putting into it!

@jannyHou @emonddr , could you please help groom this task so that the team can estimate? Thanks!

We can use the same pattern as @intercept - https://github.com/strongloop/loopback-next/blob/master/packages/context/src/interceptor.ts#L339.

The decorator allows to be applied at both class and method level.

Related to #1334

I need some time to study the interceptors pattern being recommended here, to understand how this would be implemented...

But in the meantime, here are some things we need to consider:

1.

If we have the @authenticate('some_strategy') decorator at the controller class level, this would mean ALL controller functions will go through authentication.

2.

If we want a few controller methods to avoid authentication in this scenario, we would need another decorator like @unauthenticated to be placed on these few controller methods. (to avoid authenticating these requests)

3.

There's a PR in the works about how default and request-level options should be handled
https://github.com/strongloop/loopback-next/pull/3194 . The current suggested approach is that a strategy class should load its default options as a class property, and that any option overrides should be specified at the request-level in the @authenticate decorator on a controller function.

So authentication with default options, the decorator parameters at the class level would look like this:

@authenticate('jwt_strategy')

No options are passed as a second parameter (no need to, the strategy class loads defaults)

If user wants to override some default option for a specific authenticated controller function, then
the @authenticate decorator would need to be place on that controller method and would look like this:

@authenticate('jwt_strategy',{ someOption: "different_value" })

@jannyHou, @raymondfeng , what are your thoughts on this? thanks

@emonddr Good idea to list various combinations. In general, the class level provides default settings and the method level can override it. To make things simple, I suggest the following:

  1. If a method is decorated with @authenticate, uses the metadata as is without checking the class
  2. If a method is not decorated with @authenticate, checks the class level
  3. Introduce @authenticate.skip or @authenticate('skip') to exclude a method to inherit @authenticate from the class

Thanks @emonddr for the summary,

I need some time to study the interceptors pattern being recommended here

I think Raymond means the class or method decorator can be created like this.

And I am good with @raymondfeng 's proposal:

If a method is decorated with @authenticate, uses the metadata as is without checking the class
If a method is not decorated with @authenticate, checks the class level
Introduce @authenticate.skip or @authenticate('skip') to exclude a method to inherit @authenticate from the class

No options are passed as a second parameter (no need to, the strategy class loads defaults)

I think the class level decorator can still take options, like each controller has its own configurations. We can leverage @config(). These are implementation details we can discuss more when start to work on this story.

Moving to Q4.

Closing as done.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

half-blood-programmer picture half-blood-programmer  路  3Comments

mhdawson picture mhdawson  路  3Comments

frodoe7 picture frodoe7  路  3Comments

rexliu0715 picture rexliu0715  路  3Comments

acrodrig picture acrodrig  路  3Comments