You have to grant on the underlying object only.
SQL> show user
USER is "HR"
SQL> select * from v$session;
select * from v$session
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> conn [email protected] as sysdba
Enter password: ******
Connected.
SQL> grant select on v_$session to hr;
Grant succeeded.
SQL> conn [email protected]
Enter password: **
Connected.
SQL> select * from v$session;
SADDR SID SERIAL# AUDSID PADDR USER#
-------- ---------- ---------- ---------- -------- ----------The main thing is definition of v$session is
create or replace public synonym V$SESSION
for SYS.V_$SESSION;and the definition of the view itself is
create or replace view v_$session as
select "SADDR","SID","SERIAL#","AUDSID","PADDR","USER#","USERNAME","COMMAND","OWNERID","TADDR","LOCKWAIT","STATUS","SERVER","SCHEMA#","SCHEMANAME","OSUSER","PROCESS","MACHINE","TERMINAL","PROGRAM","TYPE","SQL_ADDRESS","SQL_HASH_VALUE","SQL_ID","SQL_CHILD_NUMBER","PREV_SQL_ADDR","PREV_HASH_VALUE","PREV_SQL_ID","PREV_CHILD_NUMBER","MODULE","MODULE_HASH","ACTION","ACTION_HASH","CLIENT_INFO","FIXED_TABLE_SEQUENCE","ROW_WAIT_OBJ#","ROW_WAIT_FILE#","ROW_WAIT_BLOCK#","ROW_WAIT_ROW#","LOGON_TIME","LAST_CALL_ET","PDML_ENABLED","FAILOVER_TYPE","FAILOVER_METHOD","FAILED_OVER","RESOURCE_CONSUMER_GROUP","PDML_STATUS","PDDL_STATUS","PQ_STATUS","CURRENT_QUEUE_DURATION","CLIENT_IDENTIFIER","BLOCKING_SESSION_STATUS","BLOCKING_INSTANCE","BLOCKING_SESSION","SEQ#","EVENT#","EVENT","P1TEXT","P1","P1RAW","P2TEXT","P2","P2RAW","P3TEXT","P3","P3RAW","WAIT_CLASS_ID","WAIT_CLASS#","WAIT_CLASS","WAIT_TIME","SECONDS_IN_WAIT","STATE","SERVICE_NAME","SQL_TRACE","SQL_TRACE_WAITS","SQL_TRACE_BINDS" from v$session