Skip to content

Commit 1d8b26b

Browse files
committed
fix token expiration type, tests and docs references.
fix invalidateAll hmac cli command. implements CanAccessTokenExpire() and CanHmacTokenExpire() methods. removes hasAccessTokenExpired() and hasHmacTokenExpired() methods.
1 parent 072fca3 commit 1d8b26b

File tree

10 files changed

+182
-164
lines changed

10 files changed

+182
-164
lines changed

docs/references/authentication/hmac.md

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -103,51 +103,52 @@ By default, the HMAC keys don't expire unless they meet the HMAC Keys lifetime e
103103

104104
HMAC keys can be set to expire through the `generateHmacToken()` method. This takes the expiration date as the $expiresAt argument. It's also possible to update an existing HMAC key using `setHmacTokenExpirationById($HmacTokenID, $expiresAt)`
105105

106-
`$expiresAt` Accepts DateTime string formatted as 'Y-m-d h:i:s' or [DateTime relative formats](https://www.php.net/manual/en/datetime.formats.php#datetime.formats.relative) unit symbols (1 day, 2 weeks, 6 months, 1 year) to be added to DateTime 'now'
106+
`$expiresAt` [Time](/libraries/time.html) object
107107

108108
```php
109109
// Expiration date = 2024-11-03 12:00:00
110-
$token = $this->user->generateHmacToken('foo', ['foo:bar'], '2024-11-03 12:00:00');
110+
$expiresAt = Time::parse('2024-11-03 12:00:00');
111+
$token = $this->user->generateHmacToken('foo', ['foo:bar'], $expiresAt);
111112

112113
// Expiration date = 2024-11-15 00:00:00
113-
$token = $user->setHmacTokenExpirationById($token->id, '2024-11-15 00:00:00');
114-
115-
// Or Expiration date = now() + 1 month + 15 days
116-
$token = $user->setHmacTokenExpirationById($token->id, '1 month 15 days');
114+
$expiresAt = Time::parse('2024-11-15 00:00:00');
115+
$token = $user->setHmacTokenExpirationById($token->id, $expiresAt);
116+
117+
// Or Expiration date = 1 month + 15 days into the future
118+
$expiresAt = Time::now();
119+
$expiresAt = $expiresAt->addMonths(1);
120+
$expiresAt = $expiresAt->addDays(15);
121+
$token = $user->setHmacTokenExpirationById($token->id, $expiresAt);
117122
```
118123

119124
The following support methods are also available:
120125

121-
`hasHmacTokenExpired(AccessToken $HmacToken)` - Checks if the given HMAC key has expired. Returns `true` if the HMAC key has expired, `false` if not, and `null` if the expire date is null.
126+
`hasHmacTokenExpired(AccessToken $HmacToken)` - Checks if the HMAC key has expired. Returns `true` if the HMAC key has expired, `false` if not, and `null` if the expire date is null.
122127

123128
```php
124-
$token = $this->user->generateAccessToken('foo', ['foo:bar'], '2024-11-03 12:00:00');
129+
$expiresAt = Time::parse('2024-11-03 12:00:00');
130+
$token = $this->user->generateHmacToken('foo', ['foo:bar'], $expiresAt);
125131

126132
$this->user->hasHmacTokenExpired($token); // Returns true
127133
```
128134

129-
`getHmacTokenTimeToExpire(AccessToken $accessToken, string $format = "date" | "human")` - Checks if the given HMAC key has expired. Returns `true` if HMAC key has expired, `false` if not, and `null` if the expire date is not set.
135+
`canHmacTokenExpire(AccessToken $HmacToken)` - Checks if HMAC key has an expiration set. Returns `true` or `false` accordingly.
130136

131137
```php
132-
$token = $this->user->generateHmacToken('foo', ['foo:bar']);
133-
134-
$this->user->getHmacTokenTimeToExpire($token, 'date'); // Returns null
135-
136-
// Assuming current time is: 2024-11-04 20:00:00
137-
$token = $this->user->generateHmacToken('foo', ['foo:bar'], '2024-11-03 12:00:00');
138+
$expiresAt = Time::parse('2024-11-03 12:00:00');
138139

139-
$this->user->getHmacTokenTimeToExpire($token, 'date'); // 2024-11-03 12:00:00
140-
$this->user->getHmacTokenTimeToExpire($token, 'human'); // 1 day ago
140+
$token = $this->user->generateHmacToken('foo', ['foo:bar'], $expiresAt);
141+
$this->user->canHmacTokenExpire($token); // Returns true
141142

142-
$token = $this->user->generateHmacToken('foo', ['foo:bar'], '2026-01-06 12:00:00');
143-
$this->user->getHmacTokenTimeToExpire($token, 'human'); // in 1 year
143+
$token2 = $this->user->generateHmacToken('bar');
144+
$this->user->canHmacTokenExpire($token2); // Returns false
144145
```
145146

146147
You can also easily set all existing HMAC keys/tokens as expired with the `spark` command:
147148
```
148-
php spark shield:hmac expireAll
149+
php spark shield:hmac invalidateAll
149150
```
150-
**Careful!** This command 'expires' _all_ keys for _all_ users.
151+
**Careful!** This command invalidates _all_ keys for _all_ users.
151152

152153
## Retrieving HMAC Keys
153154

docs/references/authentication/tokens.md

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -144,46 +144,50 @@ By default, the Access Tokens don't expire unless they meet the Access Token lif
144144

145145
Access Tokens can be set to expire through the `generateAccessToken()` method. This takes the expiration date as the $expiresAt argument. It's also possible to update an existing HMAC key using `setAccessTokenById($HmacTokenID, $expiresAt)`
146146

147-
`$expiresAt` Accepts DateTime string formatted as 'Y-m-d h:i:s' or [DateTime relative formats](https://www.php.net/manual/en/datetime.formats.php#datetime.formats.relative) unit symbols (1 day, 2 weeks, 6 months, 1 year) to be added to DateTime 'now'
147+
`$expiresAt` [Time](/libraries/time.html) object
148148

149149
```php
150150
// Expiration date = 2024-11-03 12:00:00
151-
$token = $this->user->generateAccessToken('foo', ['foo:bar'], '2024-11-03 12:00:00');
151+
$expiresAt = Time::parse('2024-11-03 12:00:00');
152+
$token = $this->user->generateAccessToken('foo', ['foo:bar'], $expiresAt);
152153

153154
// Expiration date = 2024-11-15 00:00:00
154-
$user->setAccessTokenExpirationById($token->id, '2024-11-15 00:00:00');
155+
$expiresAt = Time::parse('2024-11-15 00:00:00');
156+
$user->setAccessTokenExpirationById($token->id, $expiresAt);
155157

156-
// Or Expiration date = now() + 1 month + 15 days
157-
$user->setAccessTokenExpirationById($token->id, '1 month 15 days');
158+
// Or Expiration date = 1 month + 15 days into the future
159+
$expiresAt = Time::now();
160+
$expiresAt = $expiresAt->addMonths(1);
161+
$expiresAt = $expiresAt->addDays(15);
162+
163+
$user->setAccessTokenExpirationById($token->id, $expiresAt);
158164
```
159165

160166
The following support methods are also available:
161167

162-
`hasAccessTokenExpired(AccessToken $accessToken)` - Checks if the given Access Token has expired. Returns `true` if the Access Token has expired, `false` if not, and `null` if the expire date is not set.
168+
`hasAccessTokenExpired(AccessToken $accessToken)` - Checks if Access Token has expired. Returns `true` if the Access Token has expired, `false` if not, and `null` if the expire date is not set.
163169

164170
```php
165-
$token = $this->user->generateAccessToken('foo', ['foo:bar'], '2024-11-03 12:00:00');
171+
$expiresAt = Time::parse('2024-11-03 12:00:00');
172+
173+
$token = $this->user->generateAccessToken('foo', ['foo:bar'], $expiresAt);
166174

167175
$this->user->hasAccessTokenExpired($token); // Returns true
168176
```
169177

170-
`getAccessTokenTimeToExpire(AccessToken $accessToken, string $format = "date" | "human")` - Checks if the given Access Token has expired. Returns `true` if Access Token has expired, `false` if not, and `null` if the expire date is null.
178+
`canAccessTokenExpire(AccessToken $HmacToken)` - Checks if Access Token has an expiration set. Returns `true` or `false` accordingly.
171179

172180
```php
173-
$token = $this->user->generateAccessToken('foo', ['foo:bar']);
174-
175-
$this->user->getAccessTokenTimeToExpire($token, 'date'); // Returns null
181+
$expiresAt = Time::parse('2024-11-03 12:00:00');
176182

177-
// Assuming current time is: 2024-11-04 20:00:00
178-
$token = $this->user->generateAccessToken('foo', ['foo:bar'], '2024-11-03 12:00:00');
183+
$token = $this->user->generateAccessToken('foo', ['foo:bar'], $expiresAt);
184+
$this->user->canAccessTokenExpire($token2); // Returns false
179185

180-
$this->user->getAccessTokenTimeToExpire($token, 'date'); // 2024-11-03 12:00:00
181-
$this->user->getAccessTokenTimeToExpire($token, 'human'); // 1 day ago
182-
183-
$token = $this->user->generateAccessToken('foo', ['foo:bar'], '2026-01-06 12:00:00');
184-
$this->user->getAccessTokenTimeToExpire($token, 'human'); // in 1 year
186+
$token2 = $this->user->generateAccessToken('bar');
187+
$this->user->canAccessTokenExpire($token); // Returns true
185188
```
186189

190+
187191
### Access Token Expiration vs Lifetime
188192
Expiration and Lifetime are different concepts. The lifetime is the maximum time allowed for the token to exist since its last use. Token expiration, on the other hand, is a set date in which the Access Token will cease to function.
189193

phpstan-baseline.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@
258258
];
259259
$ignoreErrors[] = [
260260
'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#',
261+
'identifier' => 'codeigniter.factoriesClassConstFetch',
261262
'count' => 21,
262263
'path' => __DIR__ . '/src/Entities/User.php',
263264
];

src/Authentication/Authenticators/AccessTokens.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ public function check(array $credentials): Result
158158
if (
159159
$token->expires !== null
160160
&& $token->expires->isBefore(
161-
Time::now()
161+
Time::now(),
162162
)
163163
) {
164164
return new Result([

src/Authentication/Traits/HasAccessTokens.php

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ trait HasAccessTokens
3939
*
4040
* @param string $name Token name
4141
* @param list<string> $scopes Permissions the token grants
42-
* @param string $expiresAt Sets token expiration date. Accepts DateTime string formatted as 'Y-m-d h:i:s' or DateTime relative formats (1 day, 2 weeks, 6 months, 1 year) to be added to DateTime 'now'
42+
* @param Time $expiresAt Expiration date
4343
*
4444
* @throws InvalidArgumentException
4545
*/
46-
public function generateAccessToken(string $name, array $scopes = ['*'], ?string $expiresAt = null): AccessToken
46+
public function generateAccessToken(string $name, array $scopes = ['*'], ?Time $expiresAt = null): AccessToken
4747
{
4848
/** @var UserIdentityModel $identityModel */
4949
$identityModel = model(UserIdentityModel::class);
@@ -175,50 +175,22 @@ public function setAccessToken(?AccessToken $accessToken): self
175175
/**
176176
* Checks if the provided Access Token has expired.
177177
*
178-
* @return bool|null Returns true if Access Token has expired, false if not, and null if the expire field is null
178+
* @return bool Returns true if Access Token has expired, false if not
179179
*/
180-
public function hasAccessTokenExpired(?AccessToken $accessToken): bool|null
180+
public function hasAccessTokenExpired(?AccessToken $accessToken): bool
181181
{
182-
return $accessToken->expires !== null ? $accessToken->expires->isBefore(Time::now()) : null;
183-
}
184-
185-
/**
186-
* Returns formatted date to expiration for provided AccessToken
187-
*
188-
* @param AccessToken $accessToken AccessToken
189-
* @param string $format The return format - "date" or "human". Date is 'Y-m-d h:i:s', human is 'in 2 weeks'
190-
*
191-
* @return string|null Returns a formatted expiration date or null if the expire field is not set.
192-
*
193-
* @throws InvalidArgumentException
194-
*/
195-
public function getAccessTokenTimeToExpire(?AccessToken $accessToken, string $format = 'date'): string|null
196-
{
197-
if (null === $accessToken->expires) {
198-
return null;
199-
}
200-
201-
switch ($format) {
202-
case 'date':
203-
return $accessToken->expires->toLocalizedString();
204-
205-
case 'human':
206-
return $accessToken->expires->humanize();
207-
208-
default:
209-
throw new InvalidArgumentException('getAccessTokenTimeToExpire(): $format argument is invalid. Expects string with "date" or "human".');
210-
}
182+
return $accessToken->expires !== null && $accessToken->expires->isBefore(Time::now());
211183
}
212184

213185
/**
214186
* Sets an expiration for Access Tokens by ID.
215187
*
216-
* @param int $id AccessTokens ID
217-
* @param string $expiresAt Expiration date. Accepts DateTime string formatted as 'Y-m-d h:i:s' or DateTime relative formats (1 day, 2 weeks, 6 months, 1 year) to be added to DateTime 'now'
188+
* @param int $id AccessTokens ID
189+
* @param Time $expiresAt Expiration date
218190
*
219191
* @return bool Returns true if expiration date is set or updated.
220192
*/
221-
public function setAccessTokenExpirationById(int $id, string $expiresAt): bool
193+
public function setAccessTokenExpirationById(int $id, Time $expiresAt): bool
222194
{
223195
/** @var UserIdentityModel $identityModel */
224196
$identityModel = model(UserIdentityModel::class);
@@ -231,4 +203,14 @@ public function setAccessTokenExpirationById(int $id, string $expiresAt): bool
231203

232204
return $result;
233205
}
206+
207+
/**
208+
* Checks if the current Hmac token can expire
209+
*
210+
* @return bool Returns true if AccessToken can expire.
211+
*/
212+
public function canAccessTokenExpire(AccessToken $accessToken): bool
213+
{
214+
return isset($accessToken->expires);
215+
}
234216
}

src/Authentication/Traits/HasHmacTokens.php

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,12 @@ trait HasHmacTokens
4040
*
4141
* @param string $name Token name
4242
* @param list<string> $scopes Permissions the token grants
43-
* @param string $expiresAt Sets token expiration date. Accepts DateTime string formatted as 'Y-m-d h:i:s' or DateTime relative formats (1 day, 2 weeks, 6 months, 1 year) to be added to DateTime 'now'
43+
* @param Time $expiresAt Expiration date
4444
*
4545
* @throws InvalidArgumentException
4646
* @throws ReflectionException
4747
*/
48-
public function generateHmacToken(string $name, array $scopes = ['*'], ?string $expiresAt = null): AccessToken
48+
public function generateHmacToken(string $name, array $scopes = ['*'], ?Time $expiresAt = null): AccessToken
4949
{
5050
/** @var UserIdentityModel $identityModel */
5151
$identityModel = model(UserIdentityModel::class);
@@ -165,50 +165,22 @@ public function setHmacToken(?AccessToken $accessToken): self
165165
/**
166166
* Checks if the provided Access Token has expired.
167167
*
168-
* @return bool|null Returns true if Access Token has expired, false if not, and null if the expire field is null
168+
* @return bool Returns true if Access Token has expired, false if not
169169
*/
170-
public function hasHmacTokenExpired(?AccessToken $accessToken): bool|null
170+
public function hasHmacTokenExpired(?AccessToken $accessToken): bool
171171
{
172-
return $accessToken->expires !== null ? $accessToken->expires->isBefore(Time::now()) : null;
173-
}
174-
175-
/**
176-
* Returns formatted date to expiration for provided Hmac Key/Token.
177-
*
178-
* @param AccessToken $accessToken AccessToken
179-
* @param string $format The return format - "date" or "human". Date is 'Y-m-d h:i:s', human is 'in 2 weeks'
180-
*
181-
* @return string|null Returns a formatted expiration date or null if the expire field is not set.
182-
*
183-
* @throws InvalidArgumentException
184-
*/
185-
public function getHmacTokenTimeToExpire(?AccessToken $accessToken, string $format = 'date'): string|null
186-
{
187-
if (null === $accessToken->expires) {
188-
return null;
189-
}
190-
191-
switch ($format) {
192-
case 'date':
193-
return $accessToken->expires->toLocalizedString();
194-
195-
case 'human':
196-
return $accessToken->expires->humanize();
197-
198-
default:
199-
throw new InvalidArgumentException('getHmacTokenTimeToExpire(): $format argument is invalid. Expects string with "date" or "human".');
200-
}
172+
return $accessToken->expires !== null && $accessToken->expires->isBefore(Time::now());
201173
}
202174

203175
/**
204176
* Sets an expiration for Hmac Key/Token by ID.
205177
*
206-
* @param int $id AccessToken ID
207-
* @param string $expiresAt Expiration date. Accepts DateTime string formatted as 'Y-m-d h:i:s' or DateTime relative formats (1 day, 2 weeks, 6 months, 1 year) to be added to DateTime 'now'
178+
* @param int $id AccessToken ID
179+
* @param Time $expiresAt Expiration date
208180
*
209181
* @return bool Returns true if expiration date is set or updated.
210182
*/
211-
public function setHmacTokenExpirationById(int $id, string $expiresAt): bool
183+
public function setHmacTokenExpirationById(int $id, Time $expiresAt): bool
212184
{
213185
/** @var UserIdentityModel $identityModel */
214186
$identityModel = model(UserIdentityModel::class);
@@ -221,4 +193,14 @@ public function setHmacTokenExpirationById(int $id, string $expiresAt): bool
221193

222194
return $result;
223195
}
196+
197+
/**
198+
* Checks if the current Hmac token can expire
199+
*
200+
* @return bool Returns true if Hmac Token can expire.
201+
*/
202+
public function canHmacTokenExpire(AccessToken $accessToken): bool
203+
{
204+
return isset($accessToken->expires);
205+
}
224206
}

0 commit comments

Comments
 (0)