Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

PL/SQL & T-SQL (Oracle and SQL Server)  Module 13 – Dynamic SQL and security in PL/SQL

Definer's rights, invoker's rights and roles

Choose AUTHID DEFINER or AUTHID CURRENT_USER for PL/SQL units, see how roles behave in each, and give callers EXECUTE on an API instead of its tables.

  • Advanced
  • 15 minutes
  • Examples run with oracle-free 23.26.3.0.0, mssql 17.0.5005.3, Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 6 of 15 minutes free
Free: AUTHID decides whose schema and privileges a unit uses · Grant EXECUTE on an API, never the tables behind it. With a pass: 2 in-depth parts and 3 interview answers, about 9 minutes.

What you will learn

  • Explain what AUTHID DEFINER and AUTHID CURRENT_USER change about name resolution and privilege checks
  • Protect tables by granting EXECUTE on an API package instead of privileges on the tables
  • Use code-based access control and ACCESSIBLE BY to limit what a unit may do and who may call it
  • Design a least-privilege layout with separate data, API and application schemas

Before you start

What you’ll learn · Before you start

What you will learn

  • Explain what AUTHID DEFINER and AUTHID CURRENT_USER change about name resolution and privilege checks
  • Protect tables by granting EXECUTE on an API package instead of privileges on the tables
  • Use code-based access control and ACCESSIBLE BY to limit what a unit may do and who may call it
  • Design a least-privilege layout with separate data, API and application schemas

Before you start

On this page

LAB’s procedure balance_dr prints 760.25 for APP_USER, a user who may not read LAB’s accounts table at all, while the same query in balance_ir fails for that user with ORA-00942. One clause decides which happens: the unit’s AUTHID, which sets whose schema its names resolve in and whose privileges are checked.

You will predict both outcomes, protect tables with an EXECUTE grant on an API, and keep every caller to the least it needs.

AUTHID decides whose schema and privileges a unit uses

Oracle’s AUTHID page says the property affects how the SQL a unit issues at run time resolves names and checks privileges; it does not affect compilation. AUTHID DEFINER, the default, makes a unit run with definer's rights: The default rights model of a PL/SQL unit, AUTHID DEFINER: while it runs, names resolve in its owner's schema and the owner's privileges are checked, with only the role PUBLIC enabled.: when it is called, CURRENT_USER and CURRENT_SCHEMA become its owner and only the role PUBLIC stays enabled. AUTHID CURRENT_USER, which the page calls the preferred usage, gives invoker's rights: A rights model where a subprogram runs with the privileges of the session that calls it, set by AUTHID CURRENT_USER. The alternative, AUTHID DEFINER, runs with the privileges of the user who created it. More in “PL/SQL procedures, functions and parameters”: nothing switches, so names resolve in the caller’s schema and the caller’s privileges and enabled roles are checked. So the owner’s roles count for nothing inside a definer’s-rights unit, while the caller’s roles do count inside an invoker’s-rights unit.

Step through APP_USER’s two calls, one to each kind of procedure:

Interactive · step by step One caller, two procedures, two sets of rights Step through both calls and watch whose name the procedure runs under and which accounts table it reads.
One caller, two procedures, two sets of rights, step 5 of 5. Showing APP_USER session, LAB procedure (runs as APP_USER), accounts (ORA-00942). In focus: LAB procedure, accounts.APP_USER sessionEXECUTE onlyLAB procedureruns as APP_USERaccountsORA-00942APP_USER.ACCOUNTS

The drawing shows the whole scene; its 5 steps are listed below.

Every step as text
  1. A caller with EXECUTE only. APP_USER may connect and has EXECUTE on LAB's two procedures. It holds no privilege on any LAB table, so a plain SELECT from lab.accounts fails with ORA-00942.
  2. The definer's-rights call. balance_dr is AUTHID DEFINER, the default. While it runs, CURRENT_USER and CURRENT_SCHEMA become LAB and only the role PUBLIC is enabled.
  3. It reads LAB's table as LAB. The name accounts resolves in LAB's schema, LAB owns the table, and the call prints 760.25. The caller reached data it could not read itself, but only through this procedure.
  4. The invoker's-rights call. balance_ir is AUTHID CURRENT_USER. Nothing switches, so it runs as APP_USER, and accounts resolves in APP_USER's own schema.
  5. The caller has no such table. APP_USER owns no table named accounts, so the call fails with ORA-00942. Naming lab.accounts would not help either, because APP_USER may not read that table.

The model follows the same rules for four calls and a grant. Press Edit, add a grant to GRANTS or a call to CALLS, and run it again:

Whose rights each call runs with, and which table it reads Python · model/rights_model.py
"""Whose rights a PL/SQL unit runs with, and where a name such as accounts resolves.

LAB owns the practice table accounts and procedures that read it: balance_dr is AUTHID DEFINER, and
balance_ir and balance_ir_lab (which names lab.accounts) are AUTHID CURRENT_USER. APP_USER holds only
EXECUTE on them. The model follows Oracle's rules for each call: a definer's-rights unit switches
CURRENT_USER and CURRENT_SCHEMA to its owner and enables only the role PUBLIC; an invoker's-rights unit
keeps the caller's. It resolves the name, checks the privilege and prints the outcome. rights_demo.sql
makes the same calls in the database. Edit CALLS or GRANTS and run it again.
"""

TABLES = {("LAB", "ACCOUNTS"): {3: "760.25"}}  # (schema, table): {account_id: balance}
UNITS = {  # unit: (owner, AUTHID, the table name its query uses)
    "LAB.BALANCE_DR": ("LAB", "DEFINER", "accounts"),
    "LAB.BALANCE_IR": ("LAB", "CURRENT_USER", "accounts"),
    "LAB.BALANCE_IR_LAB": ("LAB", "CURRENT_USER", "lab.accounts"),
}
GRANTS = {("APP_USER", "EXECUTE", "LAB.BALANCE_DR"), ("APP_USER", "EXECUTE", "LAB.BALANCE_IR"),
          ("APP_USER", "EXECUTE", "LAB.BALANCE_IR_LAB")}


def can(user, privilege, obj):
    return obj.split(".")[0] == user or (user, privilege, obj) in GRANTS  # owners hold every privilege


def call(session_user, unit, account_id):
    owner, authid, name = UNITS[unit]
    if not can(session_user, "EXECUTE", unit):
        return session_user, "-", "PLS-00201: identifier must be declared"
    # DEFINER: the owner's identity and schema, only PUBLIC enabled; CURRENT_USER: the caller's, unchanged.
    current_user = owner if authid == "DEFINER" else session_user
    schema, table = name.upper().split(".") if "." in name else (current_user, name.upper())
    target = f"{schema}.{table}"
    if (schema, table) not in TABLES or not can(current_user, "SELECT", target):
        # Oracle gives the same error for a table that is missing and one the user may not read.
        return current_user, target, f'ORA-00942: table or view "{schema}"."{table}" does not exist'
    return current_user, target, f"balance {TABLES[(schema, table)][account_id]}"


CALLS = [
    ("APP_USER", "LAB.BALANCE_DR"),
    ("APP_USER", "LAB.BALANCE_IR"),
    ("APP_USER", "LAB.BALANCE_IR_LAB"),
    ("LAB", "LAB.BALANCE_IR"),
]
print("Each call reads the balance of account 3")
for who, unit in CALLS:
    current_user, target, outcome = call(who, unit, 3)
    print(f"  {who:<8} calls {unit:<18} runs as {current_user:<8} reads {target:<16} -> {outcome}")

GRANTS.add(("APP_USER", "SELECT", "LAB.ACCOUNTS"))
print("After GRANT SELECT ON lab.accounts TO app_user")
for who, unit in [("APP_USER", "LAB.BALANCE_IR_LAB")]:
    current_user, target, outcome = call(who, unit, 3)
    print(f"  {who:<8} calls {unit:<18} runs as {current_user:<8} reads {target:<16} -> {outcome}")

Output

Each call reads the balance of account 3
  APP_USER calls LAB.BALANCE_DR     runs as LAB      reads LAB.ACCOUNTS     -> balance 760.25
  APP_USER calls LAB.BALANCE_IR     runs as APP_USER reads APP_USER.ACCOUNTS -> ORA-00942: table or view "APP_USER"."ACCOUNTS" does not exist
  APP_USER calls LAB.BALANCE_IR_LAB runs as APP_USER reads LAB.ACCOUNTS     -> ORA-00942: table or view "LAB"."ACCOUNTS" does not exist
  LAB      calls LAB.BALANCE_IR     runs as LAB      reads LAB.ACCOUNTS     -> balance 760.25
After GRANT SELECT ON lab.accounts TO app_user
  APP_USER calls LAB.BALANCE_IR_LAB runs as APP_USER reads LAB.ACCOUNTS     -> balance 760.25

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 rights_model.py

Only the definer’s-rights call reads the balance for APP_USER. balance_ir_lab names lab.accounts, so it finds the table, yet still fails with ORA-00942, because Oracle reports that error both for a missing table and for one the user may not read. A trigger always behaves as definer’s rights and an anonymous block as invoker’s rights. For the dynamic SQL of the previous lesson, both steps happen once, at run time; static SQL is also checked at compile time, as if the unit were definer’s rights.

The script makes the same calls on the practice schema as APP_USER, then a direct SELECT that fails the same way:

rights_demo.sql: definer's and invoker's rights for a second user SQL · rights/rights_demo.sql
-- Engine: Oracle AI Database 26ai Free, Release 23.26.3.0.0; PDB FREEPDB1. Client: SQL*Plus or SQLcl.
-- Definer's rights against invoker's rights for a second user. Step 1 runs as an administrator of the lab PDB,
-- step 2 as LAB, step 3 as APP_USER. The password is asked for at run time with ACCEPT ... HIDE, never written in the
-- script and never shown: SET VERIFY OFF keeps SQL*Plus from printing the line with the value put in.
-- examples/model/rights_model.py prints the same outcomes.
SET SERVEROUTPUT ON
SET VERIFY OFF

-- Step 1, as an administrator: a second user who may only connect.
ACCEPT app_user_password CHAR PROMPT 'Password for APP_USER: ' HIDE
CREATE USER app_user IDENTIFIED BY "&app_user_password";
GRANT CREATE SESSION TO app_user;

-- Step 2, as LAB: three procedures that read the balance of one account.
CREATE OR REPLACE PROCEDURE balance_dr (p_id IN NUMBER) AUTHID DEFINER IS
  v_balance accounts.balance%TYPE;
BEGIN
  SELECT balance INTO v_balance FROM accounts WHERE account_id = p_id;   -- runs as LAB: LAB.ACCOUNTS
  DBMS_OUTPUT.PUT_LINE('balance ' || v_balance);
END;
/
CREATE OR REPLACE PROCEDURE balance_ir (p_id IN NUMBER) AUTHID CURRENT_USER IS
  v_balance accounts.balance%TYPE;
BEGIN
  SELECT balance INTO v_balance FROM accounts WHERE account_id = p_id;   -- runs as the caller: caller.ACCOUNTS
  DBMS_OUTPUT.PUT_LINE('balance ' || v_balance);
END;
/
CREATE OR REPLACE PROCEDURE balance_ir_lab (p_id IN NUMBER) AUTHID CURRENT_USER IS
  v_balance lab.accounts.balance%TYPE;
BEGIN
  SELECT balance INTO v_balance FROM lab.accounts WHERE account_id = p_id;  -- LAB.ACCOUNTS, caller's privileges
  DBMS_OUTPUT.PUT_LINE('balance ' || v_balance);
END;
/
GRANT EXECUTE ON balance_dr TO app_user;
GRANT EXECUTE ON balance_ir TO app_user;
GRANT EXECUTE ON balance_ir_lab TO app_user;

-- Step 3, as APP_USER, who holds no privilege on any LAB table.
EXEC lab.balance_dr(3)
-- Expected: balance 760.25
EXEC lab.balance_ir(3)
-- Expected: ORA-00942: table or view "APP_USER"."ACCOUNTS" does not exist
EXEC lab.balance_ir_lab(3)
-- Expected: ORA-00942: table or view "LAB"."ACCOUNTS" does not exist (APP_USER may not read it)
SELECT balance FROM lab.accounts WHERE account_id = 3;
-- Expected: ORA-00942 as well: EXECUTE on balance_dr gave APP_USER no access to the table itself

-- Step 4, as an administrator, once APP_USER has disconnected: remove the lab user.
DROP USER app_user CASCADE;
rights_demo.sql, run in the lab Python · rights_demo_session.py
"""rights_demo.sql in the lab, step by step, each in the client it names: an administrator (SYS in FREEPDB1),
LAB and APP_USER. The password of APP_USER is made for the run and given to the script's ACCEPT; it is
never shown."""

from oracle_session import Lab

STEP = r"^-- Step \d+, as (?P<who>an administrator|LAB|APP_USER)\b"
WHO = {"an administrator": ["admin"], "LAB": ["lab"], "APP_USER": ["app_user"]}

with Lab() as lab:
    typed = {"app_user_password": lab.new_password("app_user")}
    lab.steps("rights/rights_demo.sql", STEP, WHO, users={"admin": "sys", "lab": "lab", "app_user": "app_user"},
              typed=typed, close={4: ["app_user"]}, errors=3)

Output

admin> Step 1, as an administrator: a second user who may only connect.
User created.


Grant succeeded.

lab> Step 2, as LAB: three procedures that read the balance of one account.
Procedure created.


Procedure created.


Procedure created.


Grant succeeded.


Grant succeeded.


Grant succeeded.

app_user> Step 3, as APP_USER, who holds no privilege on any LAB table.
balance 760.25

PL/SQL procedure successfully completed.

BEGIN lab.balance_ir(3); END;

*
ERROR at line 1:
ORA-00942: table or view "APP_USER"."ACCOUNTS" does not exist
ORA-06512: at "LAB.BALANCE_IR", line 4
ORA-06512: at line 1
Help: https://docs.oracle.com/error-help/db/ora-00942/


BEGIN lab.balance_ir_lab(3); END;

*
ERROR at line 1:
ORA-00942: table or view "LAB"."ACCOUNTS" does not exist
ORA-06512: at "LAB.BALANCE_IR_LAB", line 4
ORA-06512: at line 1
Help: https://docs.oracle.com/error-help/db/ora-00942/


SELECT balance FROM lab.accounts WHERE account_id = 3
                        *
ERROR at line 1:
ORA-00942: table or view "LAB"."ACCOUNTS" does not exist
Help: https://docs.oracle.com/error-help/db/ora-00942/

admin> Step 4, as an administrator, once APP_USER has disconnected: remove the lab user.
User dropped.

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 rights_demo_session.py

Checkpoint

Check: What AUTHID DEFINER and CURRENT_USER change

  1. Question 1 of 3 LAB's procedure balance_dr is AUTHID DEFINER and selects from accounts. APP_USER calls it. Which table does accounts name?

    Choose one answer.

    Show the answer: Question 1 of 3

    Answer: LAB.ACCOUNTS, because the unit runs with LAB as CURRENT_USER and CURRENT_SCHEMA

    Definer's rights: the owner's schema and the owner's direct privileges.

  2. Question 2 of 3 balance_ir is AUTHID CURRENT_USER and selects from accounts. APP_USER owns no such table and calls it. What happens?

    Choose one answer.

    Show the answer: Question 2 of 3

    Answer: ORA-00942, because accounts resolves in APP_USER's schema, where no such table exists

    Invoker's rights: the caller's schema and the caller's privileges.

  3. Question 3 of 3 A procedure is created with no AUTHID clause. How does it run?

    Choose one answer.

    Show the answer: Question 3 of 3

    Answer: With definer's rights, the default

    Write AUTHID explicitly on every unit, so a reader never has to remember the default.

Grant EXECUTE on an API, never the tables behind it

The rights model turns into a design rule. APP_USER needs to read balances and make deposits, so it gets EXECUTE on one definer’s-rights package and no privilege on any table. The package checks every request, refusing a deposit that is not positive, and a direct UPDATE of the table from APP_USER fails with ORA-00942. This is least privilege: The rule that each user, login or role holds the rights its job needs and no others, so a bug or a stolen password can do as little as possible. More in “Security for T-SQL code: permissions and chains” in practice: a bug or a stolen password in the application can do only what the package allows. Answer two questions about a unit to choose its AUTHID:

Interactive · answer and compare Definer's rights or invoker's rights? Answer two questions about the unit; the table marks the choice that fits and the one ruled out.
Should callers change data they may not read or change themselves?
Should each caller work on the tables of their own schema?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

AUTHID DEFINER and AUTHID CURRENT_USER, against what the unit reads and whose privileges it uses
AUTHID Whose tables names reach Whose privileges count What to watch
Definer's rights Written as: AUTHID DEFINER Good the owner's, the same for every caller Mixed the owner's direct grants, with only PUBLIC enabled Mixed callers act with the owner's power, so keep it small
Invoker's rights Written as: AUTHID CURRENT_USER Good the caller's own schema Good the caller's, as if the caller ran the SQL Mixed every caller needs privileges on what it reads
How the answers decide
  • “Should callers change data they may not read or change themselves?” Yes, only through this unit: rules out Invoker's rights. Only a definer's-rights unit lets a caller reach the owner's data, and only in the ways the unit allows.
  • “Should callers change data they may not read or change themselves?” No, only what they already may and “Should each caller work on the tables of their own schema?” Yes, one copy per schema: rules out Definer's rights. An invoker's-rights unit resolves names in the caller's schema and checks the caller's own privileges.
  • “Should callers change data they may not read or change themselves?” No, only what they already may and “Should each caller work on the tables of their own schema?” No, one shared set of tables: adds a caveat to Definer's rights. An invoker's-rights unit that names the shared tables keeps every caller to the privileges they already hold.

Several tools tighten the pattern further. A role granted to the package itself, called code-based access control: Granting a database role to a PL/SQL function, procedure or package itself, so that the role is enabled while that unit runs and the unit holds privileges its callers do not., gives a unit privileges that no user holds. ACCESSIBLE BY: A clause that lists the PL/SQL units allowed to call a package or one of its subprograms; any other caller is refused with PLS-00904, whatever privileges it holds. More in “PL/SQL packages, session state and ORA-04068” limits which units may call a package. A layout of separate data, API and application schemas keeps each account to one job. DB_DEVELOPER_ROLE: A predefined Oracle role, from Oracle Database 23ai, that gives application developers most of the privileges they need to build and deploy applications, offered as a narrower choice than the DBA role. gives developers what they need without DBA, and a schema privilege grants one system privilege on a single schema.

Key idea

A definer’s-rights API is a door that opens with the owner’s keys. Give callers EXECUTE on the door, never privileges on the tables behind it, and keep the door’s own rules inside the package.

Checkpoint

Check: EXECUTE on an API instead of the tables

  1. Question 1 of 2 APP_USER has EXECUTE on LAB's definer's-rights account_api and nothing else. It runs UPDATE lab.accounts SET balance = 0. What happens?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: ORA-00942, because EXECUTE on the package gives no privilege on the table

    Callers reach the data only through what the API does, with its own checks.

  2. Question 2 of 2 A shared helper formats and writes a report into the caller's own report table, and callers must not touch other schemas. Which AUTHID fits?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: AUTHID CURRENT_USER, so names resolve in each caller's schema with the caller's privileges

    Definer's rights for a door into the owner's data; invoker's rights for a tool that works on the caller's own.

Roles, code-based access control and ACCESSIBLE BY, in seven cases Pro: opens with a Pro, Premium or Ultimate pass

A definer’s-rights package that gets its privileges through a role fails in two different ways, and a role granted to the package itself repairs one of them. Seven cases on a three-schema copy of the practice data show each rule, with ACCESSIBLE BY closing the door on direct calls.

In this part:

  • Why a role does not reach inside a definer’s-rights unit, worked through four cases
  • Granting a role to the unit itself
  • ACCESSIBLE BY: only the listed units may call

3 runnable examples (Python, SQL) · about 5 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

A least-privilege layout: data, API and application schemas Pro: opens with a Pro, Premium or Ultimate pass

The same practice data can be split across three schemas so that the application’s account can reach the tables only through one package. The grants, the roles for developers and reports, and the things that never belong in PL/SQL source are set out below.

In this part:

  • Three schemas and one door, worked through
  • A developer role and schema privileges instead of DBA and ANY
  • A dictionary check that fails on a weak layout
  • What stays out of PL/SQL source

2 runnable examples (Python, SQL) · about 4 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Practise: eight privilege puzzles

Each puzzle gives a caller, a unit with its AUTHID and the grants in force. Decide what the call returns, then read why each answer is right or wrong:

Practice that adapts to you

Practise this lesson

8 questions about 4 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 8 Puzzle 1: APP_USER holds only EXECUTE on LAB.balance_dr (AUTHID DEFINER), which selects the balance of account 3 from accounts. What does the call print?

    Choose one answer.

    Show the answer: Question 1 of 8

    Answer: balance 760.25

    A definer's-rights unit lends its owner's rights to the caller, for that unit's code only.

  2. Question 2 of 8 Puzzle 2: APP_USER calls LAB.balance_ir (AUTHID CURRENT_USER), which selects from accounts. APP_USER owns no table of that name. What happens?

    Choose one answer.

    Show the answer: Question 2 of 8

    Answer: ORA-00942, because accounts resolves in APP_USER's schema

    The same SQL text means a different table under invoker's rights.

  3. Question 3 of 8 Puzzle 3: APP_USER now creates its own empty table accounts with the same columns and calls LAB.balance_ir(3) again. What happens?

    Choose one answer.

    Show the answer: Question 3 of 8

    Answer: The SELECT INTO finds no row in APP_USER.ACCOUNTS and raises NO_DATA_FOUND

    This is why invoker's-rights units suit tools that work on each caller's own copy of a table.

  4. Question 4 of 8 Puzzle 4: a role with SELECT on lab.accounts is granted to APP_USER and enabled. APP_USER calls LAB.balance_ir_lab (AUTHID CURRENT_USER), which names lab.accounts. What happens?

    Choose one answer.

    Show the answer: Question 4 of 8

    Answer: balance 760.25, because an invoker's-rights unit checks the caller's enabled roles

    Roles: switched off in definer's rights, kept in invoker's rights.

  5. Question 5 of 8 Puzzle 5: APP_USER, with no privilege on lab.accounts, runs an anonymous block that selects from lab.accounts. What happens?

    Choose one answer.

    Show the answer: Question 5 of 8

    Answer: ORA-00942, because an anonymous block runs with the rights of the user who runs it

    Anonymous blocks behave as invoker's rights; triggers behave as definer's rights.

  6. Question 6 of 8 Puzzle 6: APP_USER holds EXECUTE on LAB.account_api, a definer's-rights package that makes deposits. It runs UPDATE lab.accounts SET balance = balance + 500 WHERE account_id = 3. What happens?

    Choose one answer.

    Show the answer: Question 6 of 8

    Answer: ORA-00942; the statement is APP_USER's own and APP_USER holds no privilege on the table

    EXECUTE on an API opens the API, not the tables behind it.

  7. Question 7 of 8 Puzzle 7: which grant lets APP_USER make deposits that always pass the package's checks, and nothing more?

    Choose one answer.

    Show the answer: Question 7 of 8

    Answer: GRANT EXECUTE ON lab.account_api TO app_user

    One EXECUTE grant on the API is the whole of the application's access.

  8. Question 8 of 8 Puzzle 8: a report fails for APP_USER, and a teammate proposes GRANT SELECT, UPDATE ON lab.accounts TO app_user as a quick fix. What is wrong with it?

    Choose one answer.

    Show the answer: Question 8 of 8

    Answer: It opens the table to every statement APP_USER can send, bypassing the API's checks, when a read function in the API would do

    Fix access problems by adding to the API, not by granting the tables behind it.

Interview questions

Warm-up (2–5 years): what changes when a procedure is created AUTHID CURRENT_USER?

Its SQL runs with the caller’s rights instead of the owner’s. Unqualified names resolve in the caller’s schema, and privileges are checked against the caller and the caller’s enabled roles. The default, AUTHID DEFINER, switches to the owner and enables only PUBLIC while the unit runs.

Three longer questions follow, on a procedure that fails for one caller, a package whose grant came through a role, and a schema layout to design. Answer each in your own words first; its first step shows where a strong answer starts:

  1. Mid to senior

    A utility procedure in schema TOOLS is created AUTHID CURRENT_USER and selects from a table named settings. It works when TOOLS runs it but fails with ORA-00942 for every other user who holds EXECUTE on it. Explain why, and give two fixes, saying when each is right.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to staff

    A definer's-rights package compiles in development, where its owner holds SELECT on a table directly. In test, the same privilege was granted to the owner through a role, and the package body does not compile. A colleague then rewrites the query as dynamic SQL, which compiles but fails at run time. Explain both failures and the right fix.

    Model answer, Pro. First step and follow-ups

  3. Senior to staff

    Design the database accounts for a small banking application on the practice tables. The application server must read balances and make deposits, analysts must query every table, and developers must deploy code. Who owns what, and what does each account hold?

    Model answer, Pro. First step and follow-ups

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What does a unit's AUTHID affect, and what does it not?

    How the SQL the unit issues at run time resolves names and checks privileges. It does not affect compilation.

  2. What happens when a definer's-rights unit is called?

    AUTHID DEFINER is the default: CURRENT_USER and CURRENT_SCHEMA become the unit's owner and only the role PUBLIC stays enabled, so the owner's roles count for nothing inside it.

  3. What does AUTHID CURRENT_USER give a unit?

    Invoker's rights, which Oracle calls the preferred usage: nothing switches, so names resolve in the caller's schema and the caller's privileges and enabled roles are checked.

  4. An invoker's-rights unit names lab.accounts and still fails with ORA-00942. Why?

    Oracle reports that error both for a table that does not exist and for one the user may not read, so naming the owner finds the table but the caller's missing privilege still refuses it.

  5. Which rights model does a trigger use, and which does an anonymous block use?

    A trigger always behaves as definer's rights and an anonymous block as invoker's rights.

  6. When are a unit's names resolved and privileges checked for dynamic and for static SQL?

    Dynamic SQL is resolved and checked once, when it runs. Static SQL is also checked when the unit compiles, with the privileges a definer's-rights unit would have.

  7. What does an application user get instead of rights on the tables?

    EXECUTE on one definer's-rights package and no privilege on any table: the package checks every request, and a direct UPDATE from the application fails with ORA-00942, so a bug or a stolen password can do only what the package allows.

  8. Which four tools tighten the pattern further?

    Code-based access control, a role granted to the package itself, which gives a unit privileges no user holds; ACCESSIBLE BY, which limits the units allowed to call it; separate data, API and application schemas; and narrow roles, such as DB_DEVELOPER_ROLE instead of DBA, with schema privileges granting one system privilege on a single schema.

Key takeaways

  • AUTHID DEFINER, the default, runs a unit as its owner with only PUBLIC enabled, and AUTHID CURRENT_USER runs it as the caller with the caller’s roles.
  • Names in a unit’s SQL resolve in the schema whose rights apply, so an invoker’s-rights unit looks for the caller’s tables, and ORA-00942 covers both a missing table and one the caller may not read.
  • Callers get EXECUTE on a definer’s-rights API and no privilege on its tables, so the package’s own checks hold for every request.
  • Roles granted to units, ACCESSIBLE BY, separate schemas and narrow roles for developers and reports all keep each account to the least it needs.

Terms in this lesson

code-based access control
Granting a database role to a PL/SQL function, procedure or package itself, so that the role is enabled while that unit runs and the unit holds privileges its callers do not.
DB_DEVELOPER_ROLE
A predefined Oracle role, from Oracle Database 23ai, that gives application developers most of the privileges they need to build and deploy applications, offered as a narrower choice than the DBA role.
definer's rights
The default rights model of a PL/SQL unit, AUTHID DEFINER: while it runs, names resolve in its owner's schema and the owner's privileges are checked, with only the role PUBLIC enabled.

References

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.