-
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #43 from irensaltali/42-improve-auth-states-and-re…
…sponses feat(auth)!: Add custom error handling to jwtAuth function
- Loading branch information
Showing
4 changed files
with
65 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,23 +1,67 @@ | ||
import { JWTPayload, jwtVerify } from 'jose'; | ||
import { JWTPayload, jwtVerify, errors } from 'jose'; | ||
import apiConfig from './api-config.json'; | ||
|
||
// Define a custom error type for clearer error handling | ||
class AuthError extends Error { | ||
statusCode: number; | ||
code: string; | ||
constructor(message: string, code: string, statusCode: number) { | ||
super(message); | ||
this.name = "AuthError"; | ||
this.code = code; | ||
this.statusCode = statusCode; | ||
} | ||
} | ||
|
||
async function jwtAuth(request: Request): Promise<JWTPayload> { | ||
try { | ||
const secret = new TextEncoder().encode(apiConfig.authorizer?.secret); | ||
const jwt = request.headers.get('Authorization')?.split(' ')[1] || ''; | ||
const secret = new TextEncoder().encode(apiConfig.authorizer?.secret); | ||
const authHeader = request.headers.get('Authorization'); | ||
if (!authHeader || !authHeader.startsWith('Bearer ')) { | ||
throw new AuthError('No token provided or token format is invalid.', "AUTH_ERROR", 401); | ||
} | ||
const jwt = authHeader.split(' ')[1]; | ||
|
||
try { | ||
const { payload, protectedHeader } = await jwtVerify(jwt, secret, { | ||
issuer: apiConfig.authorizer?.issuer, | ||
audience: apiConfig.authorizer?.audience, | ||
}); | ||
|
||
console.log('JWT verification successful:', payload, protectedHeader); | ||
|
||
return payload; | ||
} catch (error) { | ||
console.error('JWT verification failed:', error); | ||
return {}; | ||
if (error instanceof errors.JOSEAlgNotAllowed) { | ||
throw new AuthError('Algorithm not allowed', error.code, 401); | ||
} else if (error instanceof errors.JWEDecryptionFailed) { | ||
throw new AuthError('Decryption failed', error.code, 401); | ||
} else if (error instanceof errors.JWEInvalid) { | ||
throw new AuthError('Invalid JWE', error.code, 401); | ||
} else if (error instanceof errors.JWTExpired) { | ||
throw new AuthError('Token has expired.', error.code, 401); | ||
} else if (error instanceof errors.JWTClaimValidationFailed) { | ||
throw new AuthError('JWT claim validation failed', error.code, 401); | ||
} else if (error instanceof errors.JWTInvalid) { | ||
throw new AuthError('Invalid JWT', error.code, 401); | ||
} else if (error instanceof errors.JWKSNoMatchingKey) { | ||
throw new AuthError('No matching key found in JWKS.', error.code, 401); | ||
} else if (error instanceof errors.JWKSInvalid) { | ||
throw new AuthError('Invalid JWKS', error.code, 401); | ||
} else if (error instanceof errors.JWKSMultipleMatchingKeys) { | ||
throw new AuthError('Multiple matching keys found in JWKS.', error.code, 401); | ||
} else if (error instanceof errors.JWKSNoMatchingKey) { | ||
throw new AuthError('No matching key in JWKS.', error.code, 401); | ||
} else if (error instanceof errors.JWSInvalid) { | ||
throw new AuthError('Invalid JWS', error.code, 401); | ||
} else if (error instanceof errors.JWSSignatureVerificationFailed) { | ||
throw new AuthError('Signature verification failed', error.code, 401); | ||
} else if (error instanceof Error) { | ||
throw new AuthError('JWT verification failed', "AUTH_ERROR", 401); | ||
} | ||
// Fallback in case error is not an instance of Error | ||
throw new AuthError('JWT verification failed due to an unexpected error.', "AUTH_ERROR", 401); | ||
} | ||
} | ||
|
||
export { jwtAuth } | ||
export { jwtAuth, AuthError } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export const noMatchResponse = () => new Response( JSON.stringify({ message: 'No match found.' }), { headers: { 'Content-Type': 'application/json' }, status: 404 }) | ||
export const unauthorizedResponse = () => new Response(JSON.stringify({ message: 'Unauthorized' }),{ headers: { 'Content-Type': 'application/json' }, status: 401 }) | ||
export const internalServerErrorResponse = () => new Response(JSON.stringify({ message: 'Internal server error' }), { headers: { 'Content-Type': 'application/json' }, status: 500 }) |