Not only is it under often estimated, but in many orgs it's also reduced to a single checkbox item on someone's go-to-market slide. ":thumbsup - we're secure now!". Instead it needs to be a constant part of the culture, in every feature from the first, and ongoing thereafter.
Depending on your use case it's worth thinking about the expiration time. I assume that's checked in your client but do you also need to invalidate tokens or downgrade permissions before they expire? In that case you might want to work with smaller expiration times or get a denylist.
Assuming you also validated the expiry date.
Assuming you also verified that the issuer matched the expected one, and that you didn't fetch keys based on the issuer that is in the token.
Also assuming that the crypto alg is the one you expected.
I have seen the two authorization approaches get co-mingled, which leads to issues.
Also, often scopes are two large.. but that's mostly an implementation choice, like read all, rather than allow access to only a specific item - maybe scopes are just less easy to handle/maintain/define for the average developer.
Correct, for me this is a must avoid at all costs. I can't imagine how hard / complex it is to manage / audit two authorization system. Unless your application need more detailed permission / smaller scope, example later.
Personally I just use the one that comes from the identity provider. In my case, keycloak's model is sufficient for my use case.
And you're right, scopes are hard and unless it's global scope, you'll need to roll your own. One good example case is github/gitlab. Global scope is the administrator access, and it's easy to set it in identity provider (as "administrator" access maybe).
However for each group / repository level, you'll need to roll your own validation.
EDIT: More often than not, it comes into business domain than technical / programming one. If you're not experienced with the business domain, no wonder you'll find it hard.
I've had the same experience. Often these are teams who experience being asked to think about access controls as a roadblock on their way to product Nirvana. Security quickly becomes something to be avoided, often right up to the point where something goes rather embarrassingly wrong.
1) These teams are usually sponsored and beholden to business instead of IT. Consequently, they care about business needs first, and good coding practices second. You can imagine how that goes, given limited project time.
2) These teams usually have poor relationships with the keepers of the IAM keys. This adversarial relationship generally takes the form of (a) IAM is asked to create an appropriate permission, (b) IAM doesn't think the way things are being done is correct and doesn't want to spend the time to correct them, (c) team just throws up their hands up and asks for a standard (overbroad) permission set.
In many places, it's easier to get an exception and admin permissions than it is to get something more specific created.
The left hand (business) saying "No one will solve this problem for us" and the right hand (IAM / security) saying "You shouldn't have to do this, so we're not going to help you" is the cause of most glaring security holes.
In a monolith, a developer doesn't even have to use an access controlled API. They can simply access sensitive data through underlying access mechanisms and return it through an inappropriate endpoint.