Skip to content

Commit 9f64c24

Browse files
committed
Performing a refresh of ReCodEx API token when frontend token is being refreshed.
1 parent 0625bf7 commit 9f64c24

File tree

3 files changed

+65
-33
lines changed

3 files changed

+65
-33
lines changed

app/helpers/Recodex/RecodexApiHelper.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,9 @@ public function getTempTokenInstance(string $token): string
225225
/**
226226
* Complete the authentication process. Use tmp token to fetch full-token and user info.
227227
* The tmp token is expected to be set as the auth token already.
228-
* @return array|null ['accessToken' => string, 'user' => RecodexUser] on success
228+
* @return array ['accessToken' => string, 'user' => RecodexUser] on success
229229
*/
230-
public function getTokenAndUser(): ?array
230+
public function getTokenAndUser(): array
231231
{
232232
Debugger::log('ReCodEx::getTokenAndUser()', Debugger::DEBUG);
233233
$body = $this->post('extensions/' . $this->extensionId);
@@ -240,6 +240,23 @@ public function getTokenAndUser(): ?array
240240
return $body;
241241
}
242242

243+
/**
244+
* Refresh the token using ReCodEx API. The current token is expected to be set as the auth token already.
245+
* @return array ['accessToken' => string, 'user' => RecodexUser] on success (same as getTokenAndUser())
246+
*/
247+
public function refreshToken(): array
248+
{
249+
Debugger::log('ReCodEx::refreshToken()', Debugger::DEBUG);
250+
$body = $this->post('login/refresh');
251+
if (!is_array($body) || empty($body['accessToken']) || empty($body['user'])) {
252+
throw new RecodexApiException("Unexpected ReCodEx API response from token refresh endpoint.");
253+
}
254+
255+
// wrap the user into a structure
256+
$body['user'] = new RecodexUser($body['user'], $this);
257+
return $body;
258+
}
259+
243260
/**
244261
* Retrieve user data.
245262
* @param string $id

app/presenters/LoginPresenter.php

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@
44

55
use App\Exceptions\ForbiddenRequestException;
66
use App\Exceptions\InvalidAccessTokenException;
7+
use App\Exceptions\NotFoundException;
78
use App\Exceptions\WrongCredentialsException;
9+
use App\Model\Entity\User;
810
use App\Model\Repository\Users;
911
use App\Helpers\RecodexApiHelper;
1012
use App\Helpers\RecodexUser;
1113
use App\Security\AccessManager;
1214
use App\Security\Roles;
1315
use App\Security\TokenScope;
1416
use Nette\Security\AuthenticationException;
17+
use Exception;
1518

1619
/**
1720
* Endpoints used to log a user in
@@ -42,6 +45,34 @@ class LoginPresenter extends BasePresenter
4245
*/
4346
public $roles;
4447

48+
/**
49+
* Split the ReCodEx API token (save it to DB and suffix to the newly generated token),
50+
* generate a new token for our frontend and send the response.
51+
* @param User $user The user to log in
52+
* @param string $token The token from ReCodEx API to split and save
53+
*/
54+
private function finalizeLogin(User $user, string $token): void
55+
{
56+
// part of the token is stored in the database, suffix goes into our token (payload)
57+
$tokenSuffix = $user->setRecodexToken($token);
58+
$user->updatedNow();
59+
$this->users->persist($user);
60+
61+
// generate our token for our frontend
62+
$token = $this->accessManager->issueToken(
63+
$user,
64+
null, // no effective role override
65+
[TokenScope::MASTER, TokenScope::REFRESH],
66+
null, // default expiration
67+
['suffix' => $tokenSuffix]
68+
);
69+
70+
$this->sendSuccessResponse([
71+
"accessToken" => $token,
72+
"user" => $user,
73+
]);
74+
}
75+
4576
/**
4677
* Log in using temp token from ReCodEx.
4778
* @POST
@@ -70,25 +101,8 @@ public function actionDefault()
70101
} else {
71102
$recodexUser->updateUser($user);
72103
}
73-
$user->updatedNow();
74-
75-
// part of the token is stored in the database, suffix goes into our token (payload)
76-
$tokenSuffix = $user->setRecodexToken($recodexResponse['accessToken']);
77-
$this->users->persist($user);
78-
79-
// generate our token for our frontend
80-
$token = $this->accessManager->issueToken(
81-
$user,
82-
null, // no effective role override
83-
[TokenScope::MASTER, TokenScope::REFRESH],
84-
null, // default expiration
85-
['suffix' => $tokenSuffix]
86-
);
87104

88-
$this->sendSuccessResponse([
89-
"accessToken" => $token,
90-
"user" => $user,
91-
]);
105+
$this->finalizeLogin($user, $recodexResponse['accessToken']);
92106
}
93107

94108
/**
@@ -104,23 +118,24 @@ public function checkRefresh()
104118
}
105119

106120
/**
107-
* Refresh the access token of current user
121+
* Refresh the access token of current user (as well as the ReCodEx API token).
108122
* @GET
109123
* @LoggedIn
124+
* @throws AuthenticationException
110125
* @throws ForbiddenRequestException
126+
* @throws NotFoundException
127+
* @throws InvalidAccessTokenException
111128
*/
112129
public function actionRefresh()
113130
{
114-
$token = $this->getAccessToken();
131+
$recodexResponse = $this->recodexApi->refreshToken();
132+
/** @var RecodexUser */
133+
$recodexUser = $recodexResponse['user'];
115134

116-
$user = $this->getCurrentUser();
117-
$this->users->flush();
135+
// Update the user entity with new info from ReCodEx.
136+
$user = $this->users->findOrThrow($recodexUser->getId());
137+
$recodexUser->updateUser($user);
118138

119-
$this->sendSuccessResponse(
120-
[
121-
"accessToken" => $this->accessManager->issueRefreshedToken($token),
122-
"user" => $user,
123-
]
124-
);
139+
$this->finalizeLogin($user, $recodexResponse['accessToken']);
125140
}
126141
}

app/security/AccessManager.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ public function getUser(AccessToken $token): User
108108
*/
109109
public function issueToken(
110110
User $user,
111-
string $effectiveRole = null,
111+
?string $effectiveRole = null,
112112
array $scopes = [],
113-
int $exp = null,
113+
?int $exp = null,
114114
array $payload = []
115115
) {
116116
if ($exp === null) {
@@ -155,7 +155,7 @@ public static function getGivenAccessToken(IRequest $request)
155155
{
156156
$accessToken = $request->getQuery("access_token");
157157
if ($accessToken !== null && Strings::length($accessToken) > 0) {
158-
return $accessToken; // the token specified in the URL is prefered
158+
return $accessToken; // the token specified in the URL is preferred
159159
}
160160

161161
// if the token is not in the URL, try to find the "Authorization" header with the bearer token

0 commit comments

Comments
 (0)