OAuth scopes control what a token can do. Database roles control what a session can touch. Together, they form the real perimeter of your system. If you manage one without the other, you’re leaving gaps big enough for mistakes and exploits to slip through.
OAuth scopes are defined in your authorization server. They describe actions: read:user, write:invoice, delete:comment. When an app requests a token, you grant scopes based on policy. That policy should match the trust level of the client and the identity of the user.
Database roles belong to your data layer. Roles define privileges: SELECT on tables, INSERT into specific schemas, EXECUTE on stored procedures. Assigning the right role means the session connected through your app can only operate inside its lane.
The problem is that scopes and roles often live in separate systems, maintained by separate teams, with no unified mapping. A token may have write:order scope, but if the app runs everything under a superuser database role, that scope is meaningless. The opposite problem is also common: the token allows a read, but the database role blocks it, leading to errors and broken features.
Effective OAuth scopes management with database roles starts with hard mapping: every scope should correspond to a database role (or a composite of roles) that matches the intended permission. This mapping should be stored, versioned, and audited. The assignment happens at connection time, so that when the app uses a token, it binds its database session to the proper role dynamically.