Role-based access control query
No, this s not the best way for several reasons:.

First, with this CTE test data common to all three runs:

with Users as ( select * from (values
        (1,'Pieter')
       ,(2,'Betty')
       ,(3,'Robert')
       ,(4,'Fred')
       ,(5,'George')
       ,(6,'Anne')
   )users(UserID,Username)
),
Roles as ( select * from (values
        (100,'Guest')
       ,(101,'Public')
       ,(  1,'Admin')
       ,(102,'Editor')
   )Roles(RoleID,RoleTitle)
),
Permissions as ( select * from (values
        (1,101)
       ,(2,101),(2,102)
       ,(3,101),(1,102)
       ,(4,101)
       ,(5,100)
       ,(6,1)
       ,(7,101),(1,102)
       ,(8,101)
   )Permissions(UserID,RoleID)
)


Your suggested SQL with results is:

select r.roleID, r.roleTitle, pu.* from roles r
    left outer join (select u.*, p.roleID as xrole from permissions p
         left join users u on p.userID = u.userID
              and p.userID = 2) pu on pu.xrole = r.roleID
         and pu.userID = 2

roleID      roleTitle UserID      Username xrole
----------- --------- ----------- -------- -----------
100         Guest     NULL        NULL     NULL
101         Public    2           Betty    101
1           Admin     NULL        NULL     NULL
102         Editor    2           Betty    102


Note that the same result is obtained if we tidy the SQL somewhat to this:

select 
    r.roleID, r.roleTitle, 
    u.UserID, u.UsrName 
from permissions p
join users       u on u.UserID = p.UserID
                  and p.UserID = 2
right join roles r on p.RoleID = r.RoleID
;

roleID      roleTitle UserID      Username
----------- --------- ----------- --------
100         Guest     NULL        NULL
101         Public    2           Betty
1           Admin     NULL        NULL
102         Editor    2           Betty



Ordering your joins can make your code much easier to read, and often avoid nested subqueries.
Always list all field names (except possibly hen referencing a subquery which already lists them). This helsp to prevent your code from breaking with minor schema changes, such as additional fields or a re-ordering of the physical layout of the fields.