Skip to content

Integrate Auth0#470

Draft
rhanka wants to merge 2 commits intodevfrom
codex/remplacer-jwt-par-auth0-avec-mode-passwordless
Draft

Integrate Auth0#470
rhanka wants to merge 2 commits intodevfrom
codex/remplacer-jwt-par-auth0-avec-mode-passwordless

Conversation

@rhanka
Copy link
Member

@rhanka rhanka commented Jun 7, 2025

Summary

  • integrate Auth0 helper
  • use Auth0 verification in authentication middleware
  • update auth controller to use Auth0 for OTP and API key generation
  • add Auth0 docs
  • add jwks-rsa dependency

Testing

  • npm test (fails: vitest not found)
  • npm run build (fails: missing dependencies)

https://chatgpt.com/codex/tasks/task_e_6843ae7f03c48325b70c311384cfbd78

Summary by CodeRabbit

  • New Features
    • Introduced passwordless authentication using Auth0, allowing users to register and log in with email-based OTPs.
    • Added an endpoint to generate API tokens with configurable validity duration.
  • Bug Fixes
    • Improved authentication flow by delegating token validation and issuance to Auth0, enhancing security and reliability.
  • Documentation
    • Updated the README with detailed instructions for configuring Auth0 integration and environment variables.
  • Tests
    • Updated authentication tests to reflect Auth0 integration, including disabling token refresh and adjusting response validations.

@coderabbitai
Copy link

coderabbitai bot commented Jun 7, 2025

Walkthrough

Auth0 passwordless authentication was integrated into the backend. New functions for sending and verifying one-time passwords (OTP) via Auth0 were added, and JWT validation now uses Auth0's JWKS. The authentication controller endpoints were refactored to use Auth0 services, including an API key generation endpoint. Documentation and tests were updated accordingly.

Changes

File(s) Change Summary
README.md Added Auth0 integration instructions, environment variables, and updated endpoint documentation.
backend/package.json Added jwks-rsa dependency; updated test script to include MOCK_AUTH0=true.
backend/src/auth0.ts New module: Auth0 integration for JWT verification, OTP sending/verification, and API key creation.
backend/src/authentification.ts Switched JWT verification from local secret to Auth0 JWKS; updated scope validation logic.
backend/src/controllers/auth.controller.ts Refactored endpoints to use Auth0 for OTP and token handling; added API key generation endpoint.
backend/src/server.spec.ts Updated tests to reflect Auth0 token response changes; disabled token refresh test.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API
    participant Auth0

    Client->>API: POST /register (email)
    API->>Auth0: POST /passwordless/start (email)
    Auth0-->>API: OTP sent confirmation
    API-->>Client: OTP sent response

    Client->>API: POST /auth (email, otp)
    API->>Auth0: POST /oauth/token (grant_type=passwordless, otp)
    Auth0-->>API: Access token
    API-->>Client: Access token

    Client->>API: POST /apikey (expiresIn)
    API->>Auth0: POST /oauth/token (grant_type=client_credentials, expires_in)
    Auth0-->>API: API token
    API-->>Client: API token
Loading

Poem

In the warren where secrets are kept,
Auth0 now guards while the backend slept.
OTPs hop swiftly, tokens leap high,
API keys sparkle as time hops by.
With passwordless magic and JWKS delight,
The code is secure—what a beautiful sight!
🐇✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@rhanka
Copy link
Member Author

rhanka commented Jun 7, 2025

🎉 Snyk checks have passed. No issues have been found so far.

security/snyk check is complete. No issues have been found. (View Details)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🔭 Outside diff range comments (1)
backend/src/controllers/auth.controller.ts (1)

1-8: 🛠️ Refactor suggestion

Remove unused imports.

Several imports are no longer used after the Auth0 integration and should be removed to keep the codebase clean.

Apply this diff to remove unused imports:

-import * as jwt from "jsonwebtoken";
import {Body, Controller, Get, Post, Route, Security, Tags, Header, Query} from 'tsoa';
import { sendOTPResponse } from '../models/entities';
import { sendAuth0OTP, verifyAuth0OTP, createApiKey } from '../auth0';
-import {userDB} from '../userDB';
-import crypto from 'crypto';
-import { validateOTP, sendOTP } from '../mail';
-import loggerStream from '../logger';
🧹 Nitpick comments (4)
README.md (1)

52-57: Add language specification to code block.

The fenced code block should specify a language for better markdown compliance and syntax highlighting.

-```
+```bash
 AUTH0_DOMAIN=<votre domaine>
 AUTH0_CLIENT_ID=<identifiant client>
 AUTH0_CLIENT_SECRET=<secret client>
 AUTH0_AUDIENCE=<audience de l'API>
-```
+```
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

52-52: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

backend/src/controllers/auth.controller.ts (3)

10-17: Remove unused log function.

The log function is defined but never used in this file.

Consider removing this unused function:

-const log = (json:any) => {
-    loggerStream.write(JSON.stringify({
-      "backend": {
-        "server-date": new Date(Date.now()).toISOString(),
-        ...json
-      }
-    }));
-}

Note: If you remove this function, also remove the loggerStream import on line 8.


42-43: Fix typo in error message.

There's a typo in the error message.

-        msg: "Coudn't send mail"
+        msg: "Couldn't send mail"

105-105: Improve type safety for the generateApiKey endpoint.

The return type Promise<any> reduces type safety. Consider defining a proper interface for the API key response.

Define a proper return type interface:

interface ApiKeyResponse {
  access_token?: string;
  token_type?: string;
  expires_in?: number;
  scope?: string;
  msg?: string;
}

Then update the method signature:

-  public async generateApiKey(@Body() body: { expiresIn: number }): Promise<any> {
+  public async generateApiKey(@Body() body: { expiresIn: number }): Promise<ApiKeyResponse> {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 54672c8 and 51e2501.

📒 Files selected for processing (5)
  • README.md (1 hunks)
  • backend/package.json (1 hunks)
  • backend/src/auth0.ts (1 hunks)
  • backend/src/authentification.ts (2 hunks)
  • backend/src/controllers/auth.controller.ts (4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
backend/src/authentification.ts (1)
backend/src/auth0.ts (1)
  • verifyAuth0Token (7-20)
backend/src/controllers/auth.controller.ts (1)
backend/src/auth0.ts (4)
  • sendAuth0OTP (22-30)
  • verifyAuth0OTP (32-43)
  • verifyAuth0Token (7-20)
  • createApiKey (45-54)
🪛 markdownlint-cli2 (0.17.2)
README.md

52-52: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: 🐳 Build docker image
🔇 Additional comments (6)
backend/package.json (1)

32-32: LGTM! Essential dependency for Auth0 integration.

The jwks-rsa package is correctly added to support Auth0's JSON Web Key Set functionality for JWT token verification.

README.md (1)

47-62: Comprehensive Auth0 documentation added.

The documentation clearly explains the Auth0 integration, required environment variables, and new authentication flow. This will help users understand the migration to Auth0-based authentication.

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

52-52: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

backend/src/authentification.ts (2)

3-3: LGTM! Correct import for Auth0 integration.

The import of verifyAuth0Token properly integrates the new Auth0 verification functionality.


51-60:

Details

❓ Verification inconclusive

Verify scope property name and improve error handling.

The migration to asynchronous Auth0 token verification looks correct, but there are a few concerns:

  1. Scope validation: The code now checks decoded.scope instead of decoded.scopes. Verify that Auth0 tokens use the singular scope property.
  2. Missing null check: The scopes parameter should be validated before iteration.
       verifyAuth0Token(token).then((decoded: any) => {
-        for (const scope of scopes) {
+        if (scopes && scopes.length > 0) {
+          for (const scope of scopes) {
             if (!decoded.scope || !decoded.scope.includes(scope)) {
               reject(new jwt.JsonWebTokenError('JWT does not contain required scope.'));
               return;
+            }
           }
-        }
+        }
         resolve(decoded);
       }).catch((err: any) => reject(err));

Please verify that Auth0 JWT tokens use the scope property (not scopes) for scope information:


🏁 Script executed:

#!/bin/bash
# Description: Verify Auth0 token structure and scope property usage
# Expected: Documentation or examples showing scope property structure

rg -A 5 -B 5 "scope.*auth0|auth0.*scope" --type md --type txt --type js --type ts

Length of output: 83


Confirm Auth0 token scope claim and validate scopes input

I wasn’t able to find any references to a scope or scopes claim in the codebase—please verify in your Auth0 tenant or official docs whether JWTs include a singular scope string (vs. an array) before relying on decoded.scope. Also, guard against scopes being null or empty to avoid runtime errors.

• Add a null/empty check for the scopes parameter before iterating.
• Confirm whether Auth0 tokens carry a decoded.scope string or a different property name.

Suggested diff:

       verifyAuth0Token(token)
         .then((decoded: any) => {
+          if (!scopes || scopes.length === 0) {
+            return resolve(decoded);
+          }
+
           for (const scope of scopes) {
             if (!decoded.scope || !decoded.scope.includes(scope)) {
               return reject(new jwt.JsonWebTokenError('JWT does not contain required scope.'));
             }
           }
         resolve(decoded);
         })
         .catch((err: any) => reject(err));

Please confirm with Auth0 documentation or your tenant’s sample JWT to ensure you’re checking the correct claim.

backend/src/auth0.ts (1)

1-4: LGTM! Appropriate imports for Auth0 functionality.

The imports correctly include all necessary dependencies for Auth0 integration: axios for HTTP requests, jwks-rsa for key management, and jsonwebtoken for verification.

backend/src/controllers/auth.controller.ts (1)

61-61:

Details

✅ Verification successful

Ensure consistent timestamp units.

The expiration calculation converts milliseconds to seconds. Verify that token.expires_in is indeed in seconds as expected by OAuth2 standards.


🌐 Web query:

What unit does Auth0 use for the expires_in field in OAuth token responses - seconds or milliseconds?

💡 Result:

The expires_in field in OAuth token responses from Auth0 is specified in seconds. This means the value represents the number of seconds until the token expires.


Expiration timestamp calculation is correct. Verified that Auth0’s expires_in value is specified in seconds, so using Math.floor(Date.now() / 1000) + token.expires_in produces the intended expiration time.

Comment on lines +32 to +43
export async function verifyAuth0OTP(email: string, otp: string) {
const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',
client_id: process.env.AUTH0_CLIENT_ID,
otp,
realm: 'email',
username: email,
audience: process.env.AUTH0_AUDIENCE,
scope: 'openid profile email offline_access'
});
return res.data;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add comprehensive input validation and error handling.

The verifyAuth0OTP function handles sensitive authentication data and should have robust validation and error handling.

 export async function verifyAuth0OTP(email: string, otp: string) {
+  if (!email || !email.includes('@')) {
+    throw new Error('Valid email address is required');
+  }
+  
+  if (!otp || otp.length < 4) {
+    throw new Error('Valid OTP code is required');
+  }
+  
+  if (!process.env.AUTH0_DOMAIN || !process.env.AUTH0_CLIENT_ID || !process.env.AUTH0_AUDIENCE) {
+    throw new Error('Required Auth0 environment variables are missing');
+  }
+  
-  const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
+  try {
+    const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
       grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',
       client_id: process.env.AUTH0_CLIENT_ID,
       otp,
       realm: 'email',
       username: email,
       audience: process.env.AUTH0_AUDIENCE,
       scope: 'openid profile email offline_access'
-  });
-  return res.data;
+    });
+    return res.data;
+  } catch (error) {
+    if (axios.isAxiosError(error)) {
+      throw new Error(`Auth0 OTP verification failed: ${error.response?.data?.error_description || error.message}`);
+    }
+    throw error;
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function verifyAuth0OTP(email: string, otp: string) {
const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',
client_id: process.env.AUTH0_CLIENT_ID,
otp,
realm: 'email',
username: email,
audience: process.env.AUTH0_AUDIENCE,
scope: 'openid profile email offline_access'
});
return res.data;
}
export async function verifyAuth0OTP(email: string, otp: string) {
if (!email || !email.includes('@')) {
throw new Error('Valid email address is required');
}
if (!otp || otp.length < 4) {
throw new Error('Valid OTP code is required');
}
if (!process.env.AUTH0_DOMAIN || !process.env.AUTH0_CLIENT_ID || !process.env.AUTH0_AUDIENCE) {
throw new Error('Required Auth0 environment variables are missing');
}
try {
const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',
client_id: process.env.AUTH0_CLIENT_ID,
otp,
realm: 'email',
username: email,
audience: process.env.AUTH0_AUDIENCE,
scope: 'openid profile email offline_access'
});
return res.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(`Auth0 OTP verification failed: ${error.response?.data?.error_description || error.message}`);
}
throw error;
}
}
🤖 Prompt for AI Agents
In backend/src/auth0.ts around lines 32 to 43, the verifyAuth0OTP function lacks
input validation and error handling. Add checks to ensure the email and otp
parameters are non-empty strings and valid formats before making the request.
Wrap the axios.post call in a try-catch block to handle potential errors
gracefully, returning or throwing meaningful error messages for failures during
the authentication process.

Comment on lines +22 to +30
export async function sendAuth0OTP(email: string) {
const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/passwordless/start`, {
client_id: process.env.AUTH0_CLIENT_ID,
connection: 'email',
send: 'code',
email
});
return res.data;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation and environment variable checks.

The sendAuth0OTP function should validate inputs and environment variables to prevent runtime errors.

 export async function sendAuth0OTP(email: string) {
+  if (!email || !email.includes('@')) {
+    throw new Error('Valid email address is required');
+  }
+  
+  if (!process.env.AUTH0_DOMAIN || !process.env.AUTH0_CLIENT_ID) {
+    throw new Error('AUTH0_DOMAIN and AUTH0_CLIENT_ID environment variables are required');
+  }
+  
   const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/passwordless/start`, {
     client_id: process.env.AUTH0_CLIENT_ID,
     connection: 'email',
     send: 'code',
     email
   });
   return res.data;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function sendAuth0OTP(email: string) {
const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/passwordless/start`, {
client_id: process.env.AUTH0_CLIENT_ID,
connection: 'email',
send: 'code',
email
});
return res.data;
}
export async function sendAuth0OTP(email: string) {
if (!email || !email.includes('@')) {
throw new Error('Valid email address is required');
}
if (!process.env.AUTH0_DOMAIN || !process.env.AUTH0_CLIENT_ID) {
throw new Error('AUTH0_DOMAIN and AUTH0_CLIENT_ID environment variables are required');
}
const res = await axios.post(
`https://${process.env.AUTH0_DOMAIN}/passwordless/start`,
{
client_id: process.env.AUTH0_CLIENT_ID,
connection: 'email',
send: 'code',
email
}
);
return res.data;
}
🤖 Prompt for AI Agents
In backend/src/auth0.ts around lines 22 to 30, the sendAuth0OTP function lacks
validation for the email input and required environment variables. Add checks to
ensure the email parameter is a valid non-empty string and verify that
AUTH0_DOMAIN and AUTH0_CLIENT_ID environment variables are defined before making
the axios request. If any validation fails, throw an appropriate error to
prevent runtime issues.

import * as jwks from 'jwks-rsa';
import * as jwt from 'jsonwebtoken';

export const auth0Client = jwks.createRemoteJWKSet(new URL(`https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add environment variable validation for AUTH0_DOMAIN.

The auth0Client creation assumes AUTH0_DOMAIN exists but doesn't validate it. This could cause runtime errors if the environment variable is missing.

+if (!process.env.AUTH0_DOMAIN) {
+  throw new Error('AUTH0_DOMAIN environment variable is required');
+}
+
 export const auth0Client = jwks.createRemoteJWKSet(new URL(`https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const auth0Client = jwks.createRemoteJWKSet(new URL(`https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`));
if (!process.env.AUTH0_DOMAIN) {
throw new Error('AUTH0_DOMAIN environment variable is required');
}
export const auth0Client = jwks.createRemoteJWKSet(
new URL(`https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`)
);
🤖 Prompt for AI Agents
In backend/src/auth0.ts at line 5, the code uses process.env.AUTH0_DOMAIN
without validating its presence, which can cause runtime errors if the
environment variable is missing. Add a check to verify that AUTH0_DOMAIN is
defined before using it, and throw a clear error or handle the missing variable
appropriately to prevent runtime failures.

Comment on lines +7 to +20
export async function verifyAuth0Token(token: string): Promise<any> {
return await jwt.verify(token, async (header, callback) => {
try {
const key = await auth0Client.getKey(header as any);
callback(null, key.publicKey || key.rsaPublicKey);
} catch (err) {
callback(err as any, undefined);
}
}, {
audience: process.env.AUTH0_AUDIENCE,
issuer: `https://${process.env.AUTH0_DOMAIN}/`,
algorithms: ['RS256']
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve type safety and add environment variable validation.

The verifyAuth0Token function correctly implements Auth0 JWT verification but has some areas for improvement:

  1. Missing environment variable validation
  2. Type casting could be more specific
  3. Return type should be more specific than any
 export async function verifyAuth0Token(token: string): Promise<any> {
+  if (!process.env.AUTH0_AUDIENCE || !process.env.AUTH0_DOMAIN) {
+    throw new Error('AUTH0_AUDIENCE and AUTH0_DOMAIN environment variables are required');
+  }
+  
   return await jwt.verify(token, async (header, callback) => {
     try {
-      const key = await auth0Client.getKey(header as any);
+      const key = await auth0Client.getKey(header as jwt.JwtHeader);
       callback(null, key.publicKey || key.rsaPublicKey);
     } catch (err) {
-      callback(err as any, undefined);
+      callback(err as Error, undefined);
     }
   }, {
     audience: process.env.AUTH0_AUDIENCE,
     issuer: `https://${process.env.AUTH0_DOMAIN}/`,
     algorithms: ['RS256']
   });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function verifyAuth0Token(token: string): Promise<any> {
return await jwt.verify(token, async (header, callback) => {
try {
const key = await auth0Client.getKey(header as any);
callback(null, key.publicKey || key.rsaPublicKey);
} catch (err) {
callback(err as any, undefined);
}
}, {
audience: process.env.AUTH0_AUDIENCE,
issuer: `https://${process.env.AUTH0_DOMAIN}/`,
algorithms: ['RS256']
});
}
export async function verifyAuth0Token(token: string): Promise<any> {
if (!process.env.AUTH0_AUDIENCE || !process.env.AUTH0_DOMAIN) {
throw new Error('AUTH0_AUDIENCE and AUTH0_DOMAIN environment variables are required');
}
return await jwt.verify(token, async (header, callback) => {
try {
const key = await auth0Client.getKey(header as jwt.JwtHeader);
callback(null, key.publicKey || key.rsaPublicKey);
} catch (err) {
callback(err as Error, undefined);
}
}, {
audience: process.env.AUTH0_AUDIENCE,
issuer: `https://${process.env.AUTH0_DOMAIN}/`,
algorithms: ['RS256']
});
}
🤖 Prompt for AI Agents
In backend/src/auth0.ts around lines 7 to 20, improve the verifyAuth0Token
function by first validating that the required environment variables
AUTH0_AUDIENCE and AUTH0_DOMAIN are defined and throwing an error if not.
Replace the generic 'any' type cast on the header parameter with a more specific
type matching the expected JWT header structure. Change the function's return
type from 'Promise<any>' to a more precise type representing the decoded JWT
payload or a defined interface for the token claims to enhance type safety.

Comment on lines +45 to +54
export async function createApiKey(expiresIn: number) {
const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
client_id: process.env.AUTH0_CLIENT_ID,
client_secret: process.env.AUTH0_CLIENT_SECRET,
audience: process.env.AUTH0_AUDIENCE,
grant_type: 'client_credentials',
expires_in: expiresIn
});
return res.data;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation and improve error handling for API key creation.

The createApiKey function should validate inputs and provide better error handling for the client credentials flow.

 export async function createApiKey(expiresIn: number) {
+  if (!expiresIn || expiresIn <= 0) {
+    throw new Error('Valid expiration time (in seconds) is required');
+  }
+  
+  if (!process.env.AUTH0_DOMAIN || !process.env.AUTH0_CLIENT_ID || !process.env.AUTH0_CLIENT_SECRET || !process.env.AUTH0_AUDIENCE) {
+    throw new Error('Required Auth0 environment variables are missing');
+  }
+  
-  const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
+  try {
+    const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
       client_id: process.env.AUTH0_CLIENT_ID,
       client_secret: process.env.AUTH0_CLIENT_SECRET,
       audience: process.env.AUTH0_AUDIENCE,
       grant_type: 'client_credentials',
       expires_in: expiresIn
-  });
-  return res.data;
+    });
+    return res.data;
+  } catch (error) {
+    if (axios.isAxiosError(error)) {
+      throw new Error(`Auth0 API key creation failed: ${error.response?.data?.error_description || error.message}`);
+    }
+    throw error;
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function createApiKey(expiresIn: number) {
const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
client_id: process.env.AUTH0_CLIENT_ID,
client_secret: process.env.AUTH0_CLIENT_SECRET,
audience: process.env.AUTH0_AUDIENCE,
grant_type: 'client_credentials',
expires_in: expiresIn
});
return res.data;
}
export async function createApiKey(expiresIn: number) {
if (!expiresIn || expiresIn <= 0) {
throw new Error('Valid expiration time (in seconds) is required');
}
if (
!process.env.AUTH0_DOMAIN ||
!process.env.AUTH0_CLIENT_ID ||
!process.env.AUTH0_CLIENT_SECRET ||
!process.env.AUTH0_AUDIENCE
) {
throw new Error('Required Auth0 environment variables are missing');
}
try {
const res = await axios.post(
`https://${process.env.AUTH0_DOMAIN}/oauth/token`,
{
client_id: process.env.AUTH0_CLIENT_ID,
client_secret: process.env.AUTH0_CLIENT_SECRET,
audience: process.env.AUTH0_AUDIENCE,
grant_type: 'client_credentials',
expires_in: expiresIn,
}
);
return res.data;
} catch (error) {
if (axios.isAxiosError(error)) {
throw new Error(
`Auth0 API key creation failed: ${
error.response?.data?.error_description || error.message
}`
);
}
throw error;
}
}
🤖 Prompt for AI Agents
In backend/src/auth0.ts around lines 45 to 54, the createApiKey function lacks
input validation and robust error handling. Add validation to ensure expiresIn
is a positive number before making the request. Wrap the axios.post call in a
try-catch block to catch and handle errors gracefully, logging or throwing
meaningful error messages to improve debugging and reliability.

💡 Verification agent

🧩 Analysis chain

Verify Auth0 client credentials flow behavior.

The createApiKey function uses expires_in parameter, but Auth0's client credentials flow typically doesn't accept this parameter for token expiration. The token lifetime is usually configured in the Auth0 dashboard.

Please verify if Auth0's client credentials grant type accepts the expires_in parameter:


🌐 Web query:

Does Auth0 client credentials grant type support expires_in parameter for token expiration?

💡 Result:

The Auth0 client credentials grant type does have a fixed expiration for access tokens, but doesn't support customizing this through an expires_in parameter in the request itself.

Token Expiration in Auth0 Client Credentials Flow

The client credentials flow in Auth0 (defined in OAuth 2.0 RFC 6749, section 4.4) provides access tokens with a default expiration time of 24 hours (86,400 seconds)[7]. However, the actual expiration time users observe is often set to one hour (3600 seconds)[5].

Configuring Token Expiration

To modify the access token expiration time for client credentials flow, you need to configure it at the API level in the Auth0 Dashboard:

  1. Navigate to API Settings in the Auth0 Dashboard (Applications > APIs)
  2. Update the "Token Expiration (Seconds)" setting[7][3]

It's important to note that Auth0 has two separate expiration settings:

  • Token Expiration (Seconds) - This applies to all flows not captured by browser flows, including client credentials
  • Token Expiration For Browser Flows (Seconds) - This applies to tokens issued via implicit and hybrid flows[3]

Limitations

There are some key limitations regarding token expiration in Auth0:

  1. You cannot set different expiration times for authorization code flow and client credentials flow using a single API configuration, as both are captured under the same expiration setting[3].

  2. The access token expiration time cannot be dynamically changed on a per-request basis[4]. Unlike some other OAuth implementations, Auth0 does not support passing an expires_in parameter during the token request to customize the token lifetime.

  3. If you need different expiration periods for different types of applications (e.g., user-facing vs. machine-to-machine), you would need to configure separate APIs in Auth0[3].

Refresh Tokens

It's worth noting that the client credentials grant type does not support refresh tokens at all[2]. This means that once an access token expires, your application must request a new access token using the client credentials again.

If you're experiencing issues with token expiration in an integration (such as with n8n), you would need to implement logic to detect expired tokens and request new ones, as some systems don't automatically handle token refresh for the client credentials flow[10].

Citations:


Remove unsupported expires_in parameter from the Auth0 client-credentials request

Auth0’s client credentials flow does not honor an expires_in request parameter—you must configure token lifetimes in the Auth0 Dashboard (Applications > APIs > Token Expiration). Please update the code accordingly:

• File: backend/src/auth0.ts (around lines 45–54)
• Remove the expiresIn parameter and the expires_in field from the POST body
• Update the function signature to no longer accept expiresIn

Suggested diff:

-export async function createApiKey(expiresIn: number) {
-  const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
-    client_id: process.env.AUTH0_CLIENT_ID,
-    client_secret: process.env.AUTH0_CLIENT_SECRET,
-    audience: process.env.AUTH0_AUDIENCE,
-    grant_type: 'client_credentials',
-    expires_in: expiresIn
-  });
+export async function createApiKey() {
+  const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
+    client_id: process.env.AUTH0_CLIENT_ID,
+    client_secret: process.env.AUTH0_CLIENT_SECRET,
+    audience: process.env.AUTH0_AUDIENCE,
+    grant_type: 'client_credentials'
+    // expires_in removed: configure token lifetime in Auth0 Dashboard
+  });
   return res.data;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function createApiKey(expiresIn: number) {
const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/oauth/token`, {
client_id: process.env.AUTH0_CLIENT_ID,
client_secret: process.env.AUTH0_CLIENT_SECRET,
audience: process.env.AUTH0_AUDIENCE,
grant_type: 'client_credentials',
expires_in: expiresIn
});
return res.data;
}
export async function createApiKey() {
const res = await axios.post(
`https://${process.env.AUTH0_DOMAIN}/oauth/token`,
{
client_id: process.env.AUTH0_CLIENT_ID,
client_secret: process.env.AUTH0_CLIENT_SECRET,
audience: process.env.AUTH0_AUDIENCE,
grant_type: 'client_credentials'
// expires_in removed: configure token lifetime in Auth0 Dashboard
}
);
return res.data;
}
🤖 Prompt for AI Agents
In backend/src/auth0.ts around lines 45 to 54, the createApiKey function
incorrectly includes an expiresIn parameter and sends an expires_in field in the
Auth0 client credentials token request, which Auth0 does not support. Remove the
expiresIn parameter from the function signature and delete the expires_in field
from the POST request body. This aligns the code with Auth0's requirement to
configure token expiration only via the Auth0 Dashboard.

this.setStatus(422);
return Promise.resolve({ msg: "Token refresh handled by Auth0" });
}
return verifyAuth0Token(token)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Import the verifyAuth0Token function.

The verifyAuth0Token function is called but not imported at the top of the file.

Add the missing import:

-import { sendAuth0OTP, verifyAuth0OTP, createApiKey } from '../auth0';
+import { sendAuth0OTP, verifyAuth0OTP, createApiKey, verifyAuth0Token } from '../auth0';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return verifyAuth0Token(token)
// At the top of backend/src/controllers/auth.controller.ts
-import { sendAuth0OTP, verifyAuth0OTP, createApiKey } from '../auth0';
+import { sendAuth0OTP, verifyAuth0OTP, createApiKey, verifyAuth0Token } from '../auth0';
🤖 Prompt for AI Agents
In backend/src/controllers/auth.controller.ts at line 89, the function
verifyAuth0Token is used but not imported. Add an import statement at the top of
the file to import verifyAuth0Token from its module to ensure the function is
available for use.

Comment on lines 83 to 84
const authHeader = Authorization || authorization;
const token = authHeader.split(' ')[1];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add validation for Authorization header format.

The code assumes the header format is "Bearer " but doesn't validate this assumption, which could cause runtime errors.

Add validation before splitting:

  ): Promise<AccessToken> {
    const authHeader = Authorization || authorization;
-   const token = authHeader.split(' ')[1];
+   if (!authHeader || !authHeader.startsWith('Bearer ')) {
+     this.setStatus(401);
+     return Promise.resolve({ msg: 'Invalid authorization header format' });
+   }
+   const token = authHeader.split(' ')[1];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const authHeader = Authorization || authorization;
const token = authHeader.split(' ')[1];
): Promise<AccessToken> {
const authHeader = Authorization || authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
this.setStatus(401);
return Promise.resolve({ msg: 'Invalid authorization header format' });
}
const token = authHeader.split(' ')[1];
🤖 Prompt for AI Agents
In backend/src/controllers/auth.controller.ts around lines 83 to 84, the code
assumes the Authorization header is in the format "Bearer <token>" without
validation, which can cause runtime errors if the format is incorrect. Add a
check to ensure authHeader exists and starts with "Bearer " before splitting. If
the validation fails, handle the error appropriately, such as returning an
unauthorized response or throwing an error.

Comment on lines 36 to +37
try {
return await sendOTP(register.user);
return await sendAuth0OTP(register.user);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify that Auth0 response matches the expected return type.

The function directly returns the Auth0 response, but it's unclear if the response structure matches the sendOTPResponse interface.

Please verify that the Auth0 passwordless start endpoint response includes the expected fields (valid and msg) required by the sendOTPResponse type:


🏁 Script executed:

#!/bin/bash
# Description: Check the sendOTPResponse interface definition to understand expected fields

# Search for sendOTPResponse type definition
ast-grep --pattern 'interface sendOTPResponse {
  $$$
}'

# Also check type or export declarations
rg -A 5 "sendOTPResponse" --type ts

Length of output: 2177


🏁 Script executed:

#!/bin/bash
# Locate and display the implementation of sendAuth0OTP
rg -nR --type ts "sendAuth0OTP" -A 20

Length of output: 442


🏁 Script executed:

#!/bin/bash
# Locate the implementation of sendAuth0OTP to inspect its return structure
rg --type ts "sendAuth0OTP" -n -C 20

Length of output: 6384


Enforce sendOTPResponse interface on Auth0 OTP call

Currently sendAuth0OTP in backend/src/auth0.ts returns res.data directly, which does not include the valid: boolean and msg: string fields defined in sendOTPResponse. You should map the Auth0 response to the expected shape before returning.

• backend/src/auth0.ts
– Update sendAuth0OTP to return a sendOTPResponse object.
• backend/src/controllers/auth.controller.ts
– Remove direct return of sendAuth0OTP data and use the mapped response.

Suggested change in backend/src/auth0.ts:

 export async function sendAuth0OTP(email: string): Promise<sendOTPResponse> {
-  const res = await axios.post(`https://${process.env.AUTH0_DOMAIN}/passwordless/start`, {
+  await axios.post(`https://${process.env.AUTH0_DOMAIN}/passwordless/start`, {
     client_id: process.env.AUTH0_CLIENT_ID,
     connection: 'email',
     send: 'code',
     email
   });
-  return res.data;
+  return {
+    valid: true,
+    msg: 'OTP code sent to email'
+  };
 }

And in backend/src/controllers/auth.controller.ts, replace:

return await sendAuth0OTP(register.user);

with:

return await sendAuth0OTP(register.user);

(implemented above to always satisfy sendOTPResponse)

🤖 Prompt for AI Agents
In backend/src/controllers/auth.controller.ts around lines 36 to 37, the code
directly returns the result of sendAuth0OTP without ensuring it matches the
sendOTPResponse interface, which requires valid:boolean and msg:string fields.
To fix this, update sendAuth0OTP in backend/src/auth0.ts to map the Auth0
response to an object conforming to sendOTPResponse by including valid and msg
fields, then in auth.controller.ts, replace the direct return with a call that
awaits sendAuth0OTP and returns the properly mapped sendOTPResponse object.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
backend/src/auth0.ts (5)

7-7: Add environment variable validation for AUTH0_DOMAIN.

The auth0Client creation assumes AUTH0_DOMAIN exists but doesn't validate it. This could cause runtime errors if the environment variable is missing.


9-33: Improve type safety and add environment variable validation.

The verifyAuth0Token function correctly implements Auth0 JWT verification but has some areas for improvement including missing environment variable validation, type casting improvements, and return type specification.


35-46: Add input validation and environment variable checks.

The sendAuth0OTP function should validate inputs and environment variables to prevent runtime errors.


48-70: Add comprehensive input validation and error handling.

The verifyAuth0OTP function handles sensitive authentication data and should have robust validation and error handling.


72-85: Remove unsupported expires_in parameter from the Auth0 client-credentials request

Auth0's client credentials flow does not honor an expires_in request parameter—you must configure token lifetimes in the Auth0 Dashboard (Applications > APIs > Token Expiration). Please update the code accordingly.

🧹 Nitpick comments (1)
README.md (1)

52-57: Specify language for fenced code block.

The environment variables code block should specify a language identifier for better syntax highlighting and accessibility.

-```
+```bash
 AUTH0_DOMAIN=<votre domaine>
 AUTH0_CLIENT_ID=<identifiant client>
 AUTH0_CLIENT_SECRET=<secret client>
 AUTH0_AUDIENCE=<audience de l'API>
-```
+```
🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

52-52: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51e2501 and 9d2ae27.

📒 Files selected for processing (4)
  • README.md (1 hunks)
  • backend/package.json (2 hunks)
  • backend/src/auth0.ts (1 hunks)
  • backend/src/server.spec.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/package.json
🧰 Additional context used
🧬 Code Graph Analysis (1)
backend/src/auth0.ts (1)
backend/src/mail.ts (2)
  • sendOTP (66-98)
  • validateOTP (100-106)
🪛 markdownlint-cli2 (0.17.2)
README.md

52-52: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: 🐳 Build docker image
🔇 Additional comments (2)
backend/src/server.spec.ts (2)

129-129: LGTM! Test expectations correctly updated for Auth0 integration.

The removal of created_at from the expected response keys correctly reflects the new Auth0 token response format.

Also applies to: 142-142


151-152: LGTM! Refresh token test correctly updated for Auth0.

The test now properly expects a 422 failure when attempting to refresh tokens locally, as token refresh is now handled by Auth0 rather than the local application.

@rhanka rhanka marked this pull request as draft June 7, 2025 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant