NestJS Passport Strategy for Firebase Auth using Firebase Admin SDK, which includes the Firebase SDK library for use.
⚠️ Important: Starting from this version, the minimum required Node.js version is 20, due to the Firebase Admin SDK v12 upgrade.
$ npm i @alpha018/nestjs-firebase-auth firebase-admin
To use Firebase authentication in your application, import the module into your main module.
import { FirebaseAuthGuard } from '@alpha018/nestjs-firebase-auth';
@Module({
imports: [
...
FirebaseAdminModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
// SELECT ONLY ONE: BASE64 OR OPTIONS (Firebase Options)!
base64: configService.get('FIREBASE_SERVICE_ACCOUNT_BASE64'), // Base64 encoded service account JSON string
options: {}, // Use this if not using base64
auth: {
config: {
extractor: ExtractJwt.fromAuthHeaderAsBearerToken(), // Choose your extractor from the Passport library
checkRevoked: true, // Set to true if you want to check for revoked Firebase tokens
validateRole: true, // Set to true if you want to validate user roles
useLocalRoles: true, // Set to true if you want to validate user roles locally without firebase call
rolesClaimKey: 'user_roles' // Set the name of the key within the Firebase custom claims that stores user roles
},
},
}),
inject: [ConfigService],
}),
...
],
})
Parameter | Type | Required | Description |
---|---|---|---|
base64 |
string |
Yes* | Base64 encoded service account JSON string. Required if options is not provided. |
options |
object |
Yes* | Firebase Admin SDK configuration options. Required if base64 is not provided. |
auth.config.extractor |
function |
Optional | A custom extractor function from the Passport library to extract the token from the request. |
auth.config.checkRevoked |
boolean |
Optional | Set to true to check if the Firebase token has been revoked. Defaults to false . |
auth.config.validateRole |
boolean |
Optional | Set to true to validate user roles using Firebase custom claims. Defaults to false . |
auth.config.useLocalRoles |
boolean |
Optional | Set to true to validate user roles using local custom claims inside the JWT token. Defaults to false . Note: If you update the claims, previously issued tokens may still contain outdated roles and remain valid. |
auth.config.rolesClaimKey |
string |
Optional | The name of the key within the Firebase custom claims that stores user roles. Defaults to 'roles' . This allows you to customize the property name for roles in your custom claims object. |
To protect an endpoint without validating user roles, use the Auth Guard to ensure the Firebase user's token is valid.
import { FirebaseGuard, FirebaseProvider } from '@alpha018/nestjs-firebase-auth';
export class AppController {
constructor(
private readonly firebaseProvider: FirebaseProvider,
) {}
@UseGuards(FirebaseGuard) // This line protects your endpoint. If `validateRole` is enabled, it also validates the user's role.
@Get()
mainFunction() {
return 'Hello World';
}
}
To enforce role-based access control, you need to set role-based custom claims in Firebase. Here's how you can set roles for a user using setClaimsRoleBase
:
import { FirebaseProvider } from '@alpha018/nestjs-firebase-auth';
enum Roles {
ADMIN,
USER,
}
@Controller('')
export class AppController {
constructor(
private readonly firebaseProvider: FirebaseProvider,
) {}
@Get()
async setUserRoles() {
await this.firebaseProvider.setClaimsRoleBase<Roles>(
'some-firebase-uid', // The UID of the user you want to set roles for
[Roles.ADMIN]
);
return { status: 'ok' }
}
}
Then, use the Auth Guard with role validation to check if a user has the necessary permissions to access an endpoint:
import { FirebaseGuard, FirebaseProvider, RolesGuard } from '@alpha018/nestjs-firebase-auth';
enum Roles {
ADMIN,
USER,
}
@Controller('')
export class AppController {
constructor(
private readonly firebaseProvider: FirebaseProvider,
) {}
@RolesGuard(Roles.ADMIN, Roles.USER) // This line checks the custom claims of the Firebase user to protect the endpoint
@UseGuards(FirebaseGuard) // This line protects your endpoint and, if `validateRole` is enabled, validates the user's role
@Get()
mainFunction() {
return 'Hello World';
}
}
To retrieve the Decoded ID Token and role claims within a protected route, use the @FirebaseUser
and @FirebaseRolesClaims
parameter decorators.
import {
FirebaseGuard,
FirebaseProvider,
FirebaseUser,
FirebaseRolesClaims,
RolesGuard,
} from '@alpha018/nestjs-firebase-auth';
import { auth } from 'firebase-admin';
enum Roles {
ADMIN,
USER,
}
@Controller('')
export class AppController {
constructor(
private readonly firebaseProvider: FirebaseProvider,
) {}
@RolesGuard(Roles.ADMIN, Roles.USER)
@UseGuards(FirebaseGuard)
@Get()
async mainFunction(
@FirebaseUser() user: auth.DecodedIdToken,
@FirebaseRolesClaims() claims: Roles[],
) {
return {
user,
claims
};
}
}
Note: Starting from version
>=1.7.x
, these two decorators are explicitly separated to avoid confusion (see issue #11):
@FirebaseUser()
→ Returns the full decoded token (auth.DecodedIdToken
).@FirebaseUserClaims()
→ Returns only the custom role claims (roles/permissions) defined for the user.
This separation ensures that developers can access both the raw Firebase user object and the role/claims information independently.
Check out a few resources that may come in handy when working with NestJS:
- Visit the NestJS Documentation to learn more about the framework.
- Visualize your application graph and interact with the NestJS application in real-time using NestJS Devtools.
- Author - Tomás Alegre
Nest is MIT licensed.