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

supabase / storage / 24849782094

23 Apr 2026 05:40PM UTC coverage: 32.29% (-39.0%) from 71.255%
24849782094

Pull #1046

github

web-flow
Merge bbd764db2 into 82d3f6383
Pull Request #1046: refactor: drop axios from tests and webhooks

1530 of 5420 branches covered (28.23%)

Branch coverage included in aggregate %.

4 of 20 new or added lines in 1 file covered. (20.0%)

3875 existing lines in 165 files now uncovered.

3317 of 9591 relevant lines covered (34.58%)

10.24 hits per line

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

6.35
/src/http/plugins/jwt.ts
1
import { verifyJWT, verifyJWTWithCache } from '@internal/auth'
2
import { getJwtSecret } from '@internal/database'
3
import { ERRORS } from '@internal/errors'
4
import fastifyPlugin from 'fastify-plugin'
5
import { JWTPayload } from 'jose'
6
import { getConfig } from '../../config'
7

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

16
  interface FastifyContextConfig {
17
    allowInvalidJwt?: boolean
18
  }
19
}
20

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

26
const { jwtCachingEnabled } = getConfig()
3✔
27

28
const BEARER = /^Bearer\s+/i
3✔
29

30
export const jwt = fastifyPlugin<JWTPluginOptions>(
3✔
31
  async (fastify, opts) => {
UNCOV
32
    fastify.decorateRequest('jwt', '')
×
UNCOV
33
    fastify.decorateRequest('jwtPayload', undefined)
×
34

UNCOV
35
    fastify.addHook('preHandler', async (request) => {
×
UNCOV
36
      if (opts.skipIfAlreadyAuthenticated && request.isAuthenticated && request.jwtPayload) {
×
37
        return
×
38
      }
39

UNCOV
40
      request.jwt = (request.headers.authorization || '').replace(BEARER, '')
×
41

UNCOV
42
      if (!request.jwt && request.routeOptions.config.allowInvalidJwt) {
×
UNCOV
43
        request.jwtPayload = { role: 'anon' }
×
UNCOV
44
        request.isAuthenticated = false
×
UNCOV
45
        return
×
46
      }
47

UNCOV
48
      const { secret, jwks } = await getJwtSecret(request.tenantId)
×
49

UNCOV
50
      try {
×
UNCOV
51
        const payload = await (jwtCachingEnabled
×
52
          ? verifyJWTWithCache(request.jwt, secret, jwks || null)
×
53
          : verifyJWT(request.jwt, secret, jwks || null))
×
54

UNCOV
55
        request.jwtPayload = payload
×
UNCOV
56
        request.owner = payload.sub
×
UNCOV
57
        request.isAuthenticated = true
×
58
      } catch (e) {
59
        request.jwtPayload = { role: 'anon' }
×
60
        request.isAuthenticated = false
×
61

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

UNCOV
70
    if (opts.enforceJwtRoles && opts.enforceJwtRoles.length > 0) {
×
UNCOV
71
      fastify.register(enforceJwtRole, {
×
72
        roles: opts.enforceJwtRoles,
73
      })
74
    }
75
  },
76
  { name: 'auth-jwt' }
77
)
78

79
interface EnforceJWTRoleOptions {
80
  roles: string[]
81
}
82

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

UNCOV
90
      const hasRoles = request.jwtPayload?.role && opts.roles.includes(request.jwtPayload.role)
×
91

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