@@ -16,6 +16,43 @@ class UserManagement
1616 public const AUTHORIZATION_PROVIDER_GOOGLE_OAUTH = "GoogleOAuth " ;
1717 public const AUTHORIZATION_PROVIDER_MICROSOFT_OAUTH = "MicrosoftOAuth " ;
1818
19+ /**
20+ * @var Session\SessionEncryptionInterface|null
21+ */
22+ private $ sessionEncryptor = null ;
23+
24+ /**
25+ * @param Session\SessionEncryptionInterface|null $encryptor Optional encryption provider
26+ */
27+ public function __construct (?Session \SessionEncryptionInterface $ encryptor = null )
28+ {
29+ $ this ->sessionEncryptor = $ encryptor ;
30+ }
31+
32+ /**
33+ * Set the session encryptor.
34+ *
35+ * @param Session\SessionEncryptionInterface $encryptor
36+ * @return void
37+ */
38+ public function setSessionEncryptor (Session \SessionEncryptionInterface $ encryptor ): void
39+ {
40+ $ this ->sessionEncryptor = $ encryptor ;
41+ }
42+
43+ /**
44+ * Get the session encryptor, defaulting to Halite.
45+ *
46+ * @return Session\SessionEncryptionInterface
47+ */
48+ private function getSessionEncryptor (): Session \SessionEncryptionInterface
49+ {
50+ if ($ this ->sessionEncryptor === null ) {
51+ $ this ->sessionEncryptor = new Session \HaliteSessionEncryption ();
52+ }
53+ return $ this ->sessionEncryptor ;
54+ }
55+
1956 /**
2057 * Create User.
2158 *
@@ -1328,4 +1365,161 @@ public function getLogoutUrl(string $sessionId, ?string $return_to = null)
13281365
13291366 return Client::generateUrl ("user_management/sessions/logout " , $ params );
13301367 }
1368+
1369+ /**
1370+ * List sessions for a user.
1371+ *
1372+ * @param string $userId User ID
1373+ * @param array $options Additional options
1374+ * - 'limit' (int): Maximum number of records to return (default: 10)
1375+ * - 'before' (string|null): Session ID to look before
1376+ * - 'after' (string|null): Session ID to look after
1377+ * - 'order' (string|null): The order in which to paginate records
1378+ *
1379+ * @return array{?string, ?string, Resource\Session[]}
1380+ * An array containing before/after cursors and array of Session instances
1381+ * @throws Exception\WorkOSException
1382+ */
1383+ public function listSessions (string $ userId , array $ options = [])
1384+ {
1385+ $ path = "user_management/users/ {$ userId }/sessions " ;
1386+
1387+ $ params = [
1388+ "limit " => $ options ['limit ' ] ?? self ::DEFAULT_PAGE_SIZE ,
1389+ "before " => $ options ['before ' ] ?? null ,
1390+ "after " => $ options ['after ' ] ?? null ,
1391+ "order " => $ options ['order ' ] ?? null
1392+ ];
1393+
1394+ $ response = Client::request (
1395+ Client::METHOD_GET ,
1396+ $ path ,
1397+ null ,
1398+ $ params ,
1399+ true
1400+ );
1401+
1402+ $ sessions = [];
1403+ list ($ before , $ after ) = Util \Request::parsePaginationArgs ($ response );
1404+
1405+ foreach ($ response ["data " ] as $ responseData ) {
1406+ \array_push ($ sessions , Resource \Session::constructFromResponse ($ responseData ));
1407+ }
1408+
1409+ return [$ before , $ after , $ sessions ];
1410+ }
1411+
1412+ /**
1413+ * Revoke a session.
1414+ *
1415+ * @param string $sessionId Session ID
1416+ *
1417+ * @return Resource\Session The revoked session
1418+ * @throws Exception\WorkOSException
1419+ */
1420+ public function revokeSession (string $ sessionId )
1421+ {
1422+ $ path = "user_management/sessions/ {$ sessionId }/revoke " ;
1423+
1424+ $ response = Client::request (
1425+ Client::METHOD_POST ,
1426+ $ path ,
1427+ null ,
1428+ null ,
1429+ true
1430+ );
1431+
1432+ return Resource \Session::constructFromResponse ($ response );
1433+ }
1434+
1435+ /**
1436+ * Authenticate with a sealed session cookie.
1437+ *
1438+ * @param string $sealedSession Encrypted session cookie data
1439+ * @param string $cookiePassword Password to decrypt the session
1440+ *
1441+ * @return Resource\SessionAuthenticationSuccessResponse|Resource\SessionAuthenticationFailureResponse
1442+ * @throws Exception\WorkOSException
1443+ */
1444+ public function authenticateWithSessionCookie (
1445+ string $ sealedSession ,
1446+ string $ cookiePassword
1447+ ) {
1448+ if (empty ($ sealedSession )) {
1449+ return new Resource \SessionAuthenticationFailureResponse (
1450+ Resource \SessionAuthenticationFailureResponse::REASON_NO_SESSION_COOKIE_PROVIDED
1451+ );
1452+ }
1453+
1454+ // Tight try/catch for unsealing only
1455+ try {
1456+ $ sessionData = $ this ->getSessionEncryptor ()->unseal ($ sealedSession , $ cookiePassword );
1457+ } catch (\Exception $ e ) {
1458+ return new Resource \SessionAuthenticationFailureResponse (
1459+ Resource \SessionAuthenticationFailureResponse::REASON_ENCRYPTION_ERROR
1460+ );
1461+ }
1462+
1463+ if (!isset ($ sessionData ['access_token ' ]) || !isset ($ sessionData ['refresh_token ' ])) {
1464+ return new Resource \SessionAuthenticationFailureResponse (
1465+ Resource \SessionAuthenticationFailureResponse::REASON_INVALID_SESSION_COOKIE
1466+ );
1467+ }
1468+
1469+ // Separate try/catch for HTTP request
1470+ try {
1471+ $ path = "user_management/sessions/authenticate " ;
1472+ $ params = [
1473+ "access_token " => $ sessionData ['access_token ' ],
1474+ "refresh_token " => $ sessionData ['refresh_token ' ]
1475+ ];
1476+
1477+ $ response = Client::request (
1478+ Client::METHOD_POST ,
1479+ $ path ,
1480+ null ,
1481+ $ params ,
1482+ true
1483+ );
1484+
1485+ return Resource \SessionAuthenticationSuccessResponse::constructFromResponse ($ response );
1486+ } catch (\Exception $ e ) {
1487+ return new Resource \SessionAuthenticationFailureResponse (
1488+ Resource \SessionAuthenticationFailureResponse::REASON_HTTP_ERROR
1489+ );
1490+ }
1491+ }
1492+
1493+ /**
1494+ * Load a sealed session and return a CookieSession instance.
1495+ *
1496+ * @param string $sealedSession Encrypted session cookie data
1497+ * @param string $cookiePassword Password to decrypt the session
1498+ *
1499+ * @return CookieSession
1500+ */
1501+ public function loadSealedSession (string $ sealedSession , string $ cookiePassword )
1502+ {
1503+ return new CookieSession ($ this , $ sealedSession , $ cookiePassword );
1504+ }
1505+
1506+ /**
1507+ * Extract and decrypt a session from HTTP cookies.
1508+ *
1509+ * @param string $cookiePassword Password to decrypt the session
1510+ * @param string $cookieName Name of the session cookie (default: 'wos-session')
1511+ *
1512+ * @return CookieSession|null
1513+ */
1514+ public function getSessionFromCookie (
1515+ string $ cookiePassword ,
1516+ string $ cookieName = 'wos-session '
1517+ ) {
1518+ if (!isset ($ _COOKIE [$ cookieName ])) {
1519+ return null ;
1520+ }
1521+
1522+ $ sealedSession = $ _COOKIE [$ cookieName ];
1523+ return $ this ->loadSealedSession ($ sealedSession , $ cookiePassword );
1524+ }
13311525}
0 commit comments