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

supabase / storage / 18404797921

10 Oct 2025 11:12AM UTC coverage: 77.143% (+0.8%) from 76.366%
18404797921

Pull #774

github

web-flow
Merge a2715e70f into 3562ba0f4
Pull Request #774: feat: vector buckets

1910 of 2761 branches covered (69.18%)

Branch coverage included in aggregate %.

2035 of 2319 new or added lines in 40 files covered. (87.75%)

23 existing lines in 2 files now uncovered.

23149 of 29723 relevant lines covered (77.88%)

95.48 hits per line

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

83.19
/src/http/plugins/jwt.ts
1
import fastifyPlugin from 'fastify-plugin'
1✔
2
import { JWTPayload } from 'jose'
1✔
3

1✔
4
import { verifyJWTWithCache, verifyJWT } from '@internal/auth'
1✔
5
import { getJwtSecret } from '@internal/database'
1✔
6
import { ERRORS } from '@internal/errors'
1✔
7
import { getConfig } from '../../config'
1✔
8

1✔
9
declare module 'fastify' {
1✔
10
  interface FastifyRequest {
1✔
11
    isAuthenticated: boolean
1✔
12
    jwt: string
1✔
13
    jwtPayload?: JWTPayload & { role?: string }
1✔
14
    owner?: string
1✔
15
  }
1✔
16

1✔
17
  interface FastifyContextConfig {
1✔
18
    allowInvalidJwt?: boolean
1✔
19
  }
1✔
20
}
1✔
21

1✔
22
interface JWTPluginOptions {
1✔
23
  enforceJwtRoles?: string[]
1✔
24
  skipIfAlreadyAuthenticated?: boolean
1✔
25
}
1✔
26

1✔
27
const { jwtCachingEnabled } = getConfig()
1✔
28

1✔
29
const BEARER = /^Bearer\s+/i
1✔
30

1✔
31
export const jwt = fastifyPlugin<JWTPluginOptions>(
1✔
32
  async (fastify, opts) => {
1✔
33
    fastify.decorateRequest('jwt', '')
976✔
34
    fastify.decorateRequest('jwtPayload', undefined)
976✔
35

976✔
36
    fastify.addHook('preHandler', async (request) => {
976✔
37
      if (opts.skipIfAlreadyAuthenticated && request.isAuthenticated && request.jwtPayload) {
100!
NEW
38
        return
×
NEW
39
      }
×
40

100✔
41
      request.jwt = (request.headers.authorization || '').replace(BEARER, '')
100✔
42

100✔
43
      if (!request.jwt && request.routeOptions.config.allowInvalidJwt) {
100✔
44
        request.jwtPayload = { role: 'anon' }
4✔
45
        request.isAuthenticated = false
4✔
46
        return
4✔
47
      }
4✔
48

96✔
49
      const { secret, jwks } = await getJwtSecret(request.tenantId)
96✔
50

96✔
51
      try {
96✔
52
        const payload = await (jwtCachingEnabled
96✔
53
          ? verifyJWTWithCache(request.jwt, secret, jwks || null)
100!
54
          : verifyJWT(request.jwt, secret, jwks || null))
100!
55

96✔
56
        request.jwtPayload = payload
96✔
57
        request.owner = payload.sub
96✔
58
        request.isAuthenticated = true
96✔
59
      } catch (e) {
100!
60
        request.jwtPayload = { role: 'anon' }
×
61
        request.isAuthenticated = false
×
62

×
63
        if (request.routeOptions.config.allowInvalidJwt) {
×
64
          return
×
65
        }
×
66
        const err = e as Error
×
67
        throw ERRORS.AccessDenied(err.message, err)
×
68
      }
×
69
    })
976✔
70

976✔
71
    if (opts.enforceJwtRoles && opts.enforceJwtRoles.length > 0) {
976✔
72
      fastify.register(enforceJwtRole, {
244✔
73
        roles: opts.enforceJwtRoles,
244✔
74
      })
244✔
75
    }
244✔
76
  },
976✔
77
  { name: 'auth-jwt' }
1✔
78
)
1✔
79

1✔
80
interface EnforceJWTRoleOptions {
1✔
81
  roles: string[]
1✔
82
}
1✔
83

1✔
84
export const enforceJwtRole = fastifyPlugin<EnforceJWTRoleOptions>(
1✔
85
  async (fastify, opts) => {
1✔
86
    fastify.addHook('preHandler', async (request) => {
366✔
87
      if (!request.isAuthenticated) {
89!
88
        throw ERRORS.AccessDenied('Access denied: JWT is not authenticated').withStatusCode(403)
×
89
      }
×
90

89✔
91
      const hasRoles = request.jwtPayload?.role && opts.roles.includes(request.jwtPayload.role)
89✔
92

89✔
93
      if (!hasRoles) {
89✔
94
        throw ERRORS.AccessDenied(`Access denied: Invalid role`).withStatusCode(403)
1✔
95
      }
1✔
96
    })
366✔
97
  },
366✔
98
  { name: 'allow-invalid-jwt' }
1✔
99
)
1✔
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