• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / auth / 25518434194

07 May 2026 07:49PM UTC coverage: 58.608% (-6.4%) from 64.989%
25518434194

push

github

web-flow
Merge pull request #47 from daycry/development

Implement security enhancements and new account features

277 of 1030 new or added lines in 55 files covered. (26.89%)

11 existing lines in 6 files now uncovered.

3544 of 6047 relevant lines covered (58.61%)

47.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

20.41
/src/Models/AccessTokenRepository.php
1
<?php
2

3
declare(strict_types=1);
4

5
/**
6
 * This file is part of Daycry Auth.
7
 *
8
 * (c) Daycry <daycry9@proton.me>
9
 *
10
 * For the full copyright and license information, please view
11
 * the LICENSE file that was distributed with this source code.
12
 */
13

14
namespace Daycry\Auth\Models;
15

16
use Daycry\Auth\Authentication\Authenticators\AccessToken;
17
use Daycry\Auth\Entities\AccessToken as AccessTokenIdentity;
18
use Daycry\Auth\Entities\User;
19
use Daycry\Auth\Services\AuditLogger;
20

21
/**
22
 * Repository for personal access token operations.
23
 *
24
 * Encapsulates all access token CRUD from UserIdentityModel
25
 * into a focused, single-responsibility class.
26
 */
27
class AccessTokenRepository
28
{
29
    public function __construct(
9✔
30
        private readonly UserIdentityModel $identityModel,
31
    ) {
32
    }
9✔
33

34
    /**
35
     * Generates a new personal access token for the user.
36
     *
37
     * @param string       $name   Token name
38
     * @param list<string> $scopes Permissions the token grants
39
     */
40
    public function generateAccessToken(User $user, string $name, array $scopes = ['*']): AccessTokenIdentity
×
41
    {
42
        return $this->identityModel->generateAccessToken($user, $name, $scopes);
×
43
    }
44

45
    /**
46
     * Finds an access token by its raw (unhashed) value.
47
     * Excludes revoked tokens.
48
     *
49
     * The query lives here (not in UserIdentityModel) because token CRUD
50
     * is the repository's responsibility — the legacy method on the
51
     * identity model is kept only as a deprecated thin wrapper.
52
     */
53
    public function getAccessTokenByRawToken(string $rawToken): ?AccessTokenIdentity
9✔
54
    {
55
        $result = $this->identityModel
9✔
56
            ->where('type', AccessToken::ID_TYPE_ACCESS_TOKEN)
9✔
57
            ->where('secret', hash('sha256', $rawToken))
9✔
58
            ->where('revoked_at')
9✔
59
            ->asObject(AccessTokenIdentity::class)
9✔
60
            ->first();
9✔
61

62
        return $result instanceof AccessTokenIdentity ? $result : null;
9✔
63
    }
64

65
    /**
66
     * Finds an access token for a specific user by raw token.
67
     */
68
    public function getAccessToken(User $user, string $rawToken): ?AccessTokenIdentity
×
69
    {
70
        return $this->identityModel->getAccessToken($user, $rawToken);
×
71
    }
72

73
    /**
74
     * Given the ID, returns the given access token.
75
     */
76
    public function getAccessTokenById(int|string $id, User $user): ?AccessTokenIdentity
×
77
    {
78
        return $this->identityModel->getAccessTokenById($id, $user);
×
79
    }
80

81
    /**
82
     * Returns all access tokens for a user.
83
     *
84
     * @return list<AccessTokenIdentity>
85
     */
86
    public function getAllAccessTokens(User $user): array
×
87
    {
88
        return $this->identityModel->getAllAccessToken($user);
×
89
    }
90

91
    /**
92
     * Hard-deletes an access token by raw token value.
93
     *
94
     * @deprecated Use softRevokeAccessToken() for soft-revocation via revoked_at.
95
     */
96
    public function deleteAccessToken(User $user, string $rawToken): void
×
97
    {
98
        $this->identityModel->revokeAccessToken($user, $rawToken);
×
99
    }
100

101
    /**
102
     * Hard-deletes an access token by its hashed secret.
103
     *
104
     * @deprecated Use softRevokeAccessTokenBySecret() for soft-revocation via revoked_at.
105
     */
106
    public function deleteAccessTokenBySecret(User $user, string $secretToken): void
×
107
    {
108
        $this->identityModel->revokeAccessTokenBySecret($user, $secretToken);
×
109
    }
110

111
    /**
112
     * Hard-deletes all access tokens for a user.
113
     *
114
     * @deprecated Use softRevokeAllAccessTokens() for soft-revocation via revoked_at.
115
     */
116
    public function deleteAllAccessTokens(User $user): void
×
117
    {
118
        $this->identityModel->revokeAllAccessToken($user);
×
119
    }
120

121
    /**
122
     * Soft-revokes an access token by setting revoked_at (by raw token).
123
     */
124
    public function softRevokeAccessToken(User $user, string $rawToken): void
×
125
    {
126
        $token = $this->identityModel->getAccessToken($user, $rawToken);
×
127

128
        if ($token !== null) {
×
129
            $this->identityModel->revokeIdentityById((int) $token->id);
×
130

NEW
131
            (new AuditLogger())->record(AuditLogger::EVENT_TOKEN_REVOKED, (int) $user->id, [
×
NEW
132
                'identity_id' => (int) $token->id,
×
NEW
133
                'token_name'  => $token->name,
×
NEW
134
            ]);
×
135
        }
136
    }
137

138
    /**
139
     * Soft-revokes an access token by its hashed secret.
140
     */
141
    public function softRevokeAccessTokenBySecret(User $user, string $secretToken): void
×
142
    {
143
        $token = $this->identityModel
×
144
            ->where('user_id', $user->id)
×
145
            ->where('type', AccessToken::ID_TYPE_ACCESS_TOKEN)
×
146
            ->where('secret', $secretToken)
×
147
            ->asObject(AccessTokenIdentity::class)
×
148
            ->first();
×
149

150
        if ($token !== null) {
×
151
            $this->identityModel->revokeIdentityById((int) $token->id);
×
152
        }
153
    }
154

155
    /**
156
     * Soft-revokes all access tokens for a user.
157
     */
158
    public function softRevokeAllAccessTokens(User $user): void
×
159
    {
160
        $this->identityModel->revokeIdentitiesByUserAndType(
×
161
            (int) $user->id,
×
162
            AccessToken::ID_TYPE_ACCESS_TOKEN,
×
163
        );
×
164

NEW
165
        (new AuditLogger())->record(AuditLogger::EVENT_TOKEN_REVOKED, (int) $user->id, [
×
NEW
166
            'scope' => 'all_access_tokens',
×
NEW
167
        ]);
×
168
    }
169
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc