Skip to content

Commit 36e0279

Browse files
committed
feat: add CookieSession class
Add CookieSession for high-level session management: - authenticate: Validate session and return user data - refresh: Refresh expired tokens and return raw tokens for re-sealing - getLogoutUrl: Generate logout URL for the session Designed to match workos-node CookieSession behavior. Sealing tokens is the responsibility of the calling code (e.g., authkit-php).
1 parent 05ac08c commit 36e0279

2 files changed

Lines changed: 400 additions & 0 deletions

File tree

lib/CookieSession.php

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<?php
2+
3+
namespace WorkOS;
4+
5+
use WorkOS\Resource\SessionAuthenticationSuccessResponse;
6+
use WorkOS\Resource\SessionAuthenticationFailureResponse;
7+
8+
/**
9+
* Class CookieSession
10+
*
11+
* Handles encrypted session cookies for user authentication and session management.
12+
* Matches workos-node CookieSession behavior - unsealing and validating sessions.
13+
*/
14+
class CookieSession
15+
{
16+
/**
17+
* @var UserManagement
18+
*/
19+
private $userManagement;
20+
21+
/**
22+
* @var string Encrypted session data
23+
*/
24+
private $sealedSession;
25+
26+
/**
27+
* @var string Cookie encryption password
28+
*/
29+
private $cookiePassword;
30+
31+
/**
32+
* Constructor.
33+
*
34+
* @param UserManagement $userManagement UserManagement instance
35+
* @param string $sealedSession Encrypted session cookie data
36+
* @param string $cookiePassword Password used to decrypt the session
37+
*/
38+
public function __construct(
39+
UserManagement $userManagement,
40+
string $sealedSession,
41+
string $cookiePassword
42+
) {
43+
$this->userManagement = $userManagement;
44+
$this->sealedSession = $sealedSession;
45+
$this->cookiePassword = $cookiePassword;
46+
}
47+
48+
/**
49+
* Authenticates the sealed session and returns user information.
50+
*
51+
* @return SessionAuthenticationSuccessResponse|SessionAuthenticationFailureResponse
52+
* @throws Exception\WorkOSException
53+
*/
54+
public function authenticate()
55+
{
56+
return $this->userManagement->authenticateWithSessionCookie(
57+
$this->sealedSession,
58+
$this->cookiePassword
59+
);
60+
}
61+
62+
/**
63+
* Refreshes an expired session and returns new tokens.
64+
*
65+
* Note: This method returns raw tokens. The calling code (e.g., authkit-php)
66+
* is responsible for sealing the tokens into a new session cookie.
67+
*
68+
* @param array $options Options for session refresh
69+
* - 'organizationId' (string|null): Organization to scope the session to
70+
*
71+
* @return array{SessionAuthenticationSuccessResponse|SessionAuthenticationFailureResponse, array|null}
72+
* Returns [response, newTokens] where newTokens contains:
73+
* - 'access_token': The new access token
74+
* - 'refresh_token': The new refresh token
75+
* - 'session_id': The session ID
76+
* Returns [failureResponse, null] on error.
77+
* @throws Exception\WorkOSException
78+
*/
79+
public function refresh(array $options = [])
80+
{
81+
$organizationId = $options['organizationId'] ?? null;
82+
83+
// First authenticate to get the current session data
84+
$authResult = $this->authenticate();
85+
86+
if (!$authResult->authenticated) {
87+
return [$authResult, null];
88+
}
89+
90+
// Tight try/catch for refresh token API call
91+
try {
92+
$refreshedAuth = $this->userManagement->authenticateWithRefreshToken(
93+
WorkOS::getClientId(),
94+
$authResult->refreshToken,
95+
null,
96+
null,
97+
$organizationId
98+
);
99+
} catch (\Exception $e) {
100+
$failureResponse = new SessionAuthenticationFailureResponse(
101+
SessionAuthenticationFailureResponse::REASON_HTTP_ERROR
102+
);
103+
return [$failureResponse, null];
104+
}
105+
106+
// Build success response
107+
$successResponse = SessionAuthenticationSuccessResponse::constructFromResponse([
108+
'authenticated' => true,
109+
'access_token' => $refreshedAuth->accessToken,
110+
'refresh_token' => $refreshedAuth->refreshToken,
111+
'session_id' => $authResult->sessionId,
112+
'user' => $refreshedAuth->user->raw,
113+
'organization_id' => $refreshedAuth->organizationId ?? $organizationId,
114+
'authentication_method' => $authResult->authenticationMethod
115+
]);
116+
117+
// Return raw tokens for the caller to seal
118+
$newTokens = [
119+
'access_token' => $refreshedAuth->accessToken,
120+
'refresh_token' => $refreshedAuth->refreshToken,
121+
'session_id' => $authResult->sessionId
122+
];
123+
124+
return [$successResponse, $newTokens];
125+
}
126+
127+
/**
128+
* Gets the logout URL for the current session.
129+
*
130+
* @param array $options
131+
* - 'returnTo' (string|null): URL to redirect to after logout
132+
*
133+
* @return string Logout URL
134+
* @throws Exception\UnexpectedValueException
135+
*/
136+
public function getLogoutUrl(array $options = [])
137+
{
138+
$authResult = $this->authenticate();
139+
140+
if (!$authResult->authenticated) {
141+
throw new Exception\UnexpectedValueException(
142+
"Cannot get logout URL for unauthenticated session"
143+
);
144+
}
145+
146+
$returnTo = $options['returnTo'] ?? null;
147+
return $this->userManagement->getLogoutUrl($authResult->sessionId, $returnTo);
148+
}
149+
}

0 commit comments

Comments
 (0)