Skip to content

Commit

Permalink
Merge pull request #9 from dead8309/firebase
Browse files Browse the repository at this point in the history
Configure Firebase Authentication and Enhancements
  • Loading branch information
anshulkumarx7 authored Jan 23, 2024
2 parents a95ce42 + ca0e256 commit f21b8e7
Show file tree
Hide file tree
Showing 17 changed files with 3,029 additions and 1,973 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
MONGODB_URL=
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
node_modules
lib
lib
!src/lib
src/service.json
.env
58 changes: 34 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,54 @@

> Faculty Review API
## Table of Contents

- [About](#about)
- [Tech Stack](#tech-stack)
- [Getting Started](#getting-started)

## About

This project uses [Feathers](http://feathersjs.com). An open source web framework for building modern real-time applications.
This is a RESTful API for the Faculty Review application.

## Tech Stack

- [NodeJS](https://nodejs.org/)
- [FeathersJS](https://feathersjs.com/)
- [MongoDB](https://www.mongodb.com/)
- [Mongoose](https://mongoosejs.com/)
- [TypeScript](https://www.typescriptlang.org/)
- [Firebase](https://firebase.google.com/)

## Getting Started

Getting up and running is as easy as 1, 2, 3.

1. Make sure you have [NodeJS](https://nodejs.org/) and [npm](https://www.npmjs.com/) installed.
2. Install your dependencies

```
cd path/to/aerofit-api-nodejs
npm install
```
3. Start your app
2. Clone this repository and install its dependencies:

```
npm start
```
```bash
git clone https://github.com/iot-lab-kiit/faculty-api-nodejs
```

## Testing
```bash
cd faculty-api-nodejs
```

Simply run `npm test` and all your tests in the `test/` directory will be run.
```bash
yarn
```

## Scaffolding
3. Configure environment variables:

Feathers has a powerful command line interface. Here are a few things it can do:
Add mongoDB connection string. Check [.env.example](.env.example) for reference.

```
$ npm install -g @feathersjs/cli # Install Feathers CLI
4. Add firebase service account

$ feathers generate service # Generate a new Service
$ feathers generate hook # Generate a new Hook
$ feathers help # Show all commands
```
Add firebase service account configs in the `src/service.json`. Check [service.json.example](service.json.example) for reference.

## Help
5. Start your app locally:

For more information on all the things you can do with Feathers visit [docs.feathersjs.com](http://docs.feathersjs.com).
```bash
yarn local
```
25 changes: 4 additions & 21 deletions config/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,9 @@
"max": 50
},
"authentication": {
"entity": "user",
"service": "users",
"oauth": {},
"secret": "KD3VmDj6rQKZqIAHEXZPEXcsHPs=",
"authStrategies": [
"jwt",
"local"
],
"jwtOptions": {
"header": {
"typ": "access"
},
"audience": "https://yourdomain.com",
"issuer": "feathers",
"algorithm": "HS256",
"expiresIn": "1d"
},
"local": {
"usernameField": "email",
"passwordField": "password"
}
},
"mongodb": "mongodb+srv://ProgrammerGod:Suvo%[email protected]/faculty_api_nodejs"
"service": "users",
"authStrategies": ["firebase"]
}
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"config": "config/"
},
"engines": {
"node": "^18.16.0",
"node": "20.5.1",
"yarn": ">= 0.18.0"
},
"scripts": {
Expand Down Expand Up @@ -52,9 +52,11 @@
"compression": "^1.7.4",
"cors": "^2.8.5",
"cron": "^2.2.0",
"dotenv": "^16.3.2",
"feathers-hooks-common": "^6.1.5",
"feathers-mongodb-fuzzy-search": "^2.0.1",
"feathers-mongoose": "^8.5.1",
"firebase-admin": "^12.0.0",
"helmet": "^5.1.0",
"mongodb-core": "^3.2.7",
"mongoose": "^6.3.6",
Expand Down
13 changes: 13 additions & 0 deletions service.json.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "",
"private_key_id": "",
"private_key": "",
"client_email": "",
"client_id": "",
"auth_uri": "",
"token_uri": "",
"auth_provider_x509_cert_url": "",
"client_x509_cert_url": "",
"universe_domain": ""
}
15 changes: 6 additions & 9 deletions src/authentication.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,19 @@
import { ServiceAddons } from '@feathersjs/feathers';
import { AuthenticationService, JWTStrategy } from '@feathersjs/authentication';
import { LocalStrategy } from '@feathersjs/authentication-local';
import { expressOauth } from '@feathersjs/authentication-oauth';

import { AuthenticationService } from '@feathersjs/authentication';
import { Application } from './declarations';
import { FirebaseJWTStrategy } from './firebase';
import { expressOauth } from '@feathersjs/authentication-oauth';

declare module './declarations' {
interface ServiceTypes {
'authentication': AuthenticationService & ServiceAddons<any>;
authentication: AuthenticationService & ServiceAddons<any>;
}
}

export default function(app: Application): void {
export default function (app: Application): void {
const authentication = new AuthenticationService(app);
authentication.register('firebase', new FirebaseJWTStrategy(app));

authentication.register('jwt', new JWTStrategy());
authentication.register('local', new LocalStrategy());

app.use('/authentication', authentication);
app.configure(expressOauth());
}
98 changes: 98 additions & 0 deletions src/firebase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import * as firebaseAdmin from 'firebase-admin';
import logger from './logger';
import { Application } from './declarations';
import { AuthenticationRequest, JWTStrategy } from '@feathersjs/authentication';
import { Params } from '@feathersjs/feathers';
import { NotAuthenticated } from '@feathersjs/errors';
import { DecodedIdToken } from 'firebase-admin/lib/auth/token-verifier';
import { initializeFirebaseAdmin } from './lib/firebase-admin';


export class FirebaseJWTStrategy extends JWTStrategy {
constructor(app: Application) {
super();
initializeFirebaseAdmin(app);
}

async authenticate(
authentication: AuthenticationRequest,
params: Params,
..._rest: any[]
): Promise<{
accessToken: any;
authentication: { strategy: string; accessToken: any; payload: any };
}> {
try {
const token = authentication.accessToken ?? authentication.access_token;
const user = await firebaseAdmin.auth().verifyIdToken(token);
if (!user) {
throw new NotAuthenticated();
}

/**
* Only create/update the user if the params.provider is rest.
*
* Params.provider will be rest when this is triggered by /authentication endpoint.
* Params.provider will be undefined when this is triggered by a service call/authenticate hook (e.g. users.create)
*/
if (params.provider === 'rest') {
logger.info('params.provider is rest, creating/updating user');
const existingUser = await this.getEntity(user.uid, params);
!existingUser ? await this.createEntity(user, params) : await this.updateEntity(existingUser, user, params);
}

return {
accessToken: token,
authentication: {
strategy: this.name!!,
accessToken: token,
payload: {
user: await this.getEntityData(user),
},
},
};
} catch (e) {
logger.error(e);
throw new NotAuthenticated();
}
}

async getEntity(id: string, params: Params): Promise<any> {
const result = await this.entityService.find({
query: {
uid: id,
},
...params,
});
const [entity = null] = result.data ? result.data : result;
return entity;
}

async createEntity(user: DecodedIdToken, params: Params) {
const data = await this.getEntityData(user, null, params);
return this.entityService.create(data, params);
}

async updateEntity(
existingEntity: any,
user: DecodedIdToken,
params: Params,
) {
const id = existingEntity['_id'];
const data = await this.getEntityData(user, existingEntity, params);
return this.entityService.patch(id, data, params);
}

async getEntityData(
user: DecodedIdToken,
_existingEntity?: any,
_params?: Params,
) {
return {
uid: user.uid,
email: user.email,
name: user.name,
pictureUrl: user.picture,
};
}
}
15 changes: 15 additions & 0 deletions src/lib/firebase-admin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as admin from 'firebase-admin';
import { Application } from '../declarations';
import * as config from "../service.json"

export const initializeFirebaseAdmin = (app: Application) => {
const firebaseConfig = config as admin.ServiceAccount;

try {
admin.initializeApp({
credential: admin.credential.cert(firebaseConfig),
});
} catch (e) {
console.log('erorr initializing firebase', e);
}
};
8 changes: 7 additions & 1 deletion src/models/users.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ export default function (app: Application): Model<any> {
unique: true,
lowercase: true,
},
password: {
uid: {
type: String,
unique: true,
required: true,
},
pictureUrl: {
type: String,
},
role: {
Expand All @@ -45,5 +50,6 @@ export default function (app: Application): Model<any> {
if (mongooseClient.modelNames().includes(modelName)) {
(mongooseClient as any).deleteModel(modelName);
}
// @ts-ignore
return mongooseClient.model<any>(modelName, schema);
}
6 changes: 3 additions & 3 deletions src/mongoose.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import mongoose from 'mongoose';
import { Application } from './declarations';
import logger from './logger';
import dotenv from 'dotenv';
dotenv.config();

export default function (app: Application): void {
mongoose.connect(
app.get('mongodb')
).catch(err => {
mongoose.connect(process.env.MONGODB_URL as string).catch(err => {
logger.error(err);
process.exit(1);
});
Expand Down
2 changes: 1 addition & 1 deletion src/services/faculties/faculties.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const { authenticate } = authentication.hooks;

export default {
before: {
all: [authenticate('jwt')],
all: [authenticate('firebase')],
find: [
SetDefaultQuery('status', ACTIVE),
search({
Expand Down
2 changes: 1 addition & 1 deletion src/services/reviews/reviews.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const { authenticate } = authentication.hooks;

export default {
before: {
all: [ authenticate('jwt') ],
all: [ authenticate('firebase') ],
find: [],
get: [],
create: [SetCreatedBy(), ProfanityCheck(), SetDefaultItem('status', ACTIVE)],
Expand Down
2 changes: 1 addition & 1 deletion src/services/subjects/subjects.hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const { authenticate } = authentication.hooks;

export default {
before: {
all: [authenticate('jwt')],
all: [authenticate('firebase')],
find: [
search({
fields: ['name', 'code'],
Expand Down
Loading

0 comments on commit f21b8e7

Please sign in to comment.