repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | import { describe, it, expect, vi, beforeEach } from 'vitest'; |
| #2 | import { verifyAccessJWT } from './jwt'; |
| #3 | |
| #4 | // Mock the jose module |
| #5 | vi.mock('jose', () => ({ |
| #6 | createRemoteJWKSet: vi.fn(() => 'mock-jwks'), |
| #7 | jwtVerify: vi.fn(), |
| #8 | })); |
| #9 | |
| #10 | describe('verifyAccessJWT', () => { |
| #11 | beforeEach(() => { |
| #12 | vi.clearAllMocks(); |
| #13 | }); |
| #14 | |
| #15 | it('calls jwtVerify with correct parameters', async () => { |
| #16 | const { jwtVerify, createRemoteJWKSet } = await import('jose'); |
| #17 | const mockPayload = { |
| #18 | email: 'test@example.com', |
| #19 | aud: ['test-aud'], |
| #20 | iss: 'https://myteam.cloudflareaccess.com', |
| #21 | exp: Math.floor(Date.now() / 1000) + 3600, |
| #22 | iat: Math.floor(Date.now() / 1000), |
| #23 | sub: 'user-id', |
| #24 | type: 'app', |
| #25 | }; |
| #26 | |
| #27 | vi.mocked(jwtVerify).mockResolvedValue({ |
| #28 | payload: mockPayload, |
| #29 | protectedHeader: { alg: 'RS256' }, |
| #30 | } as never); |
| #31 | |
| #32 | const result = await verifyAccessJWT( |
| #33 | 'test.jwt.token', |
| #34 | 'myteam.cloudflareaccess.com', |
| #35 | 'test-aud' |
| #36 | ); |
| #37 | |
| #38 | expect(createRemoteJWKSet).toHaveBeenCalledWith( |
| #39 | new URL('https://myteam.cloudflareaccess.com/cdn-cgi/access/certs') |
| #40 | ); |
| #41 | |
| #42 | expect(jwtVerify).toHaveBeenCalledWith('test.jwt.token', 'mock-jwks', { |
| #43 | issuer: 'https://myteam.cloudflareaccess.com', |
| #44 | audience: 'test-aud', |
| #45 | }); |
| #46 | |
| #47 | expect(result.email).toBe('test@example.com'); |
| #48 | }); |
| #49 | |
| #50 | it('handles team domain with https:// prefix', async () => { |
| #51 | const { jwtVerify, createRemoteJWKSet } = await import('jose'); |
| #52 | const mockPayload = { |
| #53 | email: 'test@example.com', |
| #54 | aud: ['test-aud'], |
| #55 | iss: 'https://myteam.cloudflareaccess.com', |
| #56 | exp: Math.floor(Date.now() / 1000) + 3600, |
| #57 | iat: Math.floor(Date.now() / 1000), |
| #58 | sub: 'user-id', |
| #59 | type: 'app', |
| #60 | }; |
| #61 | |
| #62 | vi.mocked(jwtVerify).mockResolvedValue({ |
| #63 | payload: mockPayload, |
| #64 | protectedHeader: { alg: 'RS256' }, |
| #65 | } as never); |
| #66 | |
| #67 | await verifyAccessJWT( |
| #68 | 'test.jwt.token', |
| #69 | 'https://myteam.cloudflareaccess.com', |
| #70 | 'test-aud' |
| #71 | ); |
| #72 | |
| #73 | expect(createRemoteJWKSet).toHaveBeenCalledWith( |
| #74 | new URL('https://myteam.cloudflareaccess.com/cdn-cgi/access/certs') |
| #75 | ); |
| #76 | |
| #77 | expect(jwtVerify).toHaveBeenCalledWith('test.jwt.token', 'mock-jwks', { |
| #78 | issuer: 'https://myteam.cloudflareaccess.com', |
| #79 | audience: 'test-aud', |
| #80 | }); |
| #81 | }); |
| #82 | |
| #83 | it('throws error when jwtVerify fails', async () => { |
| #84 | const { jwtVerify } = await import('jose'); |
| #85 | |
| #86 | vi.mocked(jwtVerify).mockRejectedValue(new Error('Invalid signature')); |
| #87 | |
| #88 | await expect( |
| #89 | verifyAccessJWT('invalid.jwt.token', 'myteam.cloudflareaccess.com', 'test-aud') |
| #90 | ).rejects.toThrow('Invalid signature'); |
| #91 | }); |
| #92 | |
| #93 | it('throws error for expired token', async () => { |
| #94 | const { jwtVerify } = await import('jose'); |
| #95 | |
| #96 | vi.mocked(jwtVerify).mockRejectedValue(new Error('"exp" claim timestamp check failed')); |
| #97 | |
| #98 | await expect( |
| #99 | verifyAccessJWT('expired.jwt.token', 'myteam.cloudflareaccess.com', 'test-aud') |
| #100 | ).rejects.toThrow('"exp" claim timestamp check failed'); |
| #101 | }); |
| #102 | |
| #103 | it('throws error for invalid audience', async () => { |
| #104 | const { jwtVerify } = await import('jose'); |
| #105 | |
| #106 | vi.mocked(jwtVerify).mockRejectedValue( |
| #107 | new Error('"aud" claim check failed') |
| #108 | ); |
| #109 | |
| #110 | await expect( |
| #111 | verifyAccessJWT('token.with.wrong-aud', 'myteam.cloudflareaccess.com', 'wrong-aud') |
| #112 | ).rejects.toThrow('"aud" claim check failed'); |
| #113 | }); |
| #114 | |
| #115 | it('throws error for invalid issuer', async () => { |
| #116 | const { jwtVerify } = await import('jose'); |
| #117 | |
| #118 | vi.mocked(jwtVerify).mockRejectedValue( |
| #119 | new Error('"iss" claim check failed') |
| #120 | ); |
| #121 | |
| #122 | await expect( |
| #123 | verifyAccessJWT('token.with.wrong-issuer', 'myteam.cloudflareaccess.com', 'test-aud') |
| #124 | ).rejects.toThrow('"iss" claim check failed'); |
| #125 | }); |
| #126 | |
| #127 | it('returns the payload on successful verification', async () => { |
| #128 | const { jwtVerify } = await import('jose'); |
| #129 | const mockPayload = { |
| #130 | email: 'user@company.com', |
| #131 | name: 'Test User', |
| #132 | aud: ['app-aud-123'], |
| #133 | iss: 'https://company.cloudflareaccess.com', |
| #134 | exp: Math.floor(Date.now() / 1000) + 3600, |
| #135 | iat: Math.floor(Date.now() / 1000), |
| #136 | sub: 'user-sub-456', |
| #137 | type: 'app', |
| #138 | }; |
| #139 | |
| #140 | vi.mocked(jwtVerify).mockResolvedValue({ |
| #141 | payload: mockPayload, |
| #142 | protectedHeader: { alg: 'RS256' }, |
| #143 | } as never); |
| #144 | |
| #145 | const result = await verifyAccessJWT( |
| #146 | 'valid.jwt.token', |
| #147 | 'company.cloudflareaccess.com', |
| #148 | 'app-aud-123' |
| #149 | ); |
| #150 | |
| #151 | expect(result).toEqual(mockPayload); |
| #152 | expect(result.email).toBe('user@company.com'); |
| #153 | expect(result.name).toBe('Test User'); |
| #154 | }); |
| #155 | }); |
| #156 |