diff --git a/services/authentication-service/README.md b/services/authentication-service/README.md index e9812c0db8..23daf94d71 100644 --- a/services/authentication-service/README.md +++ b/services/authentication-service/README.md @@ -142,6 +142,36 @@ npm i @sourceloop/authentication-service - Use `/verify-otp` to enter otp or code from authenticator app. for using Google Authenticator user needs to pass client id in the payload which is optional in case for OTP +- **Oauth- using Cognito** - + - Make sure your AWS Cognito setup is properly configured. You can refer to the official documentation [here](https://docs.aws.amazon.com/cognito/latest/developerguide/authentication.html). + - Add the following environment variables: + + COGNITO_AUTH_CALLBACK_URL= \ + COGNITO_AUTH_CLIENT_DOMAIN=\ + COGNITO_AUTH_CLIENT_ID=\ + COGNITO_AUTH_CLIENT_SECRET=\ + COGNITO_AUTH_REGION= + + COGNITO_AUTH_CALLBACK_URL should point to the /auth/cognito-auth-redirect endpoint provided by the authentication service. + - Add NODE_TLS_REJECT_UNAUTHORIZED=0 in environment to disables TLS/SSL certificate validation in Node.js. for ***Development only***. + - We are using the loopback4-authentication package in the backend service. The User, AuthClient, and UserCredential models, along with the /auth/cognito and /auth/cognito-auth-redirect APIs, have been set up in the authentication service. You only need to bind the required providers as described in the [loopback4-authentication](https://github.com/sourcefuse/loopback4-authentication) + - When the application is redirected back with the authorization code generated by the callback API, the application can send this code to the /auth/token endpoint to obtain the access token for your application. + - Create an auth_client entry in your database using the query below: + + ```typescript + INSERT INTO auth_clients (client_id, client_secret, secret) + VALUES ('temp_client', 'temp_secret', 'secret'); + ``` + Use the client_id and client_secret to invoke the auth/cognito API from the frontend. + - Additionally, configure the redirect_url for this auth client to point to the frontend URL where you want the user to be redirected after successful authorization from Cognito. The user will be redirected to this URL with a code query parameter, which can then be exchanged for a token using the /auth/token endpoint. + - The OAuth endpoints are meant to be accessed from a web browser, not from API testing tools. The API explorer shows you + the endpoint structure, but you must test OAuth flows through: + - Your frontend application + - A real browser session + - Tools specifically designed for OAuth testing (like Postman with proper OAuth 2.0 support) + + Kindly create a Dummy web App to hit and manage the apis. + - **OAuth- using Azure AD** - - Passport strategy for authenticating via Azure Ad using [passport-azure-ad](https://www.npmjs.com/package/passport-azure-ad). @@ -528,6 +558,8 @@ sequenceDiagram Here is a sample Implementation `DataSource` implementation using environment variables and PostgreSQL as the data source. The `auth-multitenant-example` utilizes both Redis and PostgreSQL as data sources. +run - ```npm install loopback-connector-postgresql --save``` + ```typescript import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core'; import {juggler} from '@loopback/repository'; @@ -562,6 +594,77 @@ export class AuthenticationDbDataSource } } ``` +redis datasource - +run - ```npm install loopback-connector-kv-redis --save``` +```typescript +for redis, datasource example is as below +import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core'; +import {AnyObject, juggler} from '@loopback/repository'; +import {readFileSync} from 'fs'; +import {AuthCacheSourceName} from '@sourceloop/authentication-service'; + +const config = { + name: process.env.REDIS_NAME, + connector: 'kv-redis', + host: process.env.REDIS_HOST, + port: process.env.REDIS_PORT, + password: process.env.REDIS_PASSWORD, + db: process.env.REDIS_DATABASE, + url: process.env.REDIS_URL, + tls: + +process.env.REDIS_TLS_ENABLED! || + (process.env.REDIS_TLS_CERT + ? { + ca: readFileSync(process.env.REDIS_TLS_CERT), + } + : undefined), + sentinels: + +process.env.REDIS_HAS_SENTINELS! && process.env.REDIS_SENTINELS + ? JSON.parse(process.env.REDIS_SENTINELS) + : undefined, + sentinelPassword: + +process.env.REDIS_HAS_SENTINELS! && process.env.REDIS_SENTINEL_PASSWORD + ? process.env.REDIS_SENTINEL_PASSWORD + : undefined, + role: + +process.env.REDIS_HAS_SENTINELS! && process.env.REDIS_SENTINEL_ROLE + ? process.env.REDIS_SENTINEL_ROLE + : undefined, +}; + +// Observe application's life cycle to disconnect the datasource when +// application is stopped. This allows the application to be shut down +// gracefully. The `stop()` method is inherited from `juggler.DataSource`. +// Learn more at https://loopback.io/doc/en/lb4/Life-cycle.html +@lifeCycleObserver('datasource') +export class RedisDataSource + extends juggler.DataSource + implements LifeCycleObserver +{ + static readonly dataSourceName = AuthCacheSourceName; + static readonly defaultConfig = config; + + constructor( + @inject(`datasources.config.${process.env.REDIS_NAME}`, {optional: true}) + dsConfig: AnyObject = config, + ) { + if ( + +process.env.REDIS_HAS_SENTINELS! && + !!process.env.REDIS_SENTINEL_HOST && + !!process.env.REDIS_SENTINEL_PORT + ) { + dsConfig.sentinels = [ + { + host: process.env.REDIS_SENTINEL_HOST, + port: +process.env.REDIS_SENTINEL_PORT, + }, + ]; + } + super(dsConfig); + } +} +``` + ### Migrations @@ -576,6 +679,51 @@ NOTE : For [`@sourceloop/cli`](https://www.npmjs.com/package/@sourceloop/cli?act ![Auth DB Schema](https://user-images.githubusercontent.com/77672713/126612271-3ce065aa-9f87-45d4-bf9a-c5cc8ad21764.jpg) +- You can use below sql to create first user. Kindly update the value of any field if required as per application requirement. + + ``` + -- Set schema + SET search_path TO main, public; + -- Auth Client + INSERT INTO auth_clients (client_id, client_secret, secret) + VALUES ('temp_client', 'temp_secret', 'secret'); + -- Tenant + INSERT INTO tenants (name, status, key) + VALUES ('Master Tenant', 1, 't1'); + -- Role + INSERT INTO roles (name, permissions, allowed_clients, role_type, tenant_id) + SELECT 'SuperAdmin', '{*}', '{temp_client}', 0, id + FROM tenants + WHERE key = 't1'; + + -- User + INSERT INTO users (first_name, last_name, username, email, default_tenant_id) + SELECT 'John', 'Doe', 'john.doe@example.com', 'john.doe@example.com', id + FROM tenants + WHERE key = 't1'; + + -- Assign User to Tenant with Role + INSERT INTO user_tenants (user_id, tenant_id, status, role_id) + SELECT + (SELECT id FROM users WHERE username = 'john.doe@example.com'), + (SELECT id FROM tenants WHERE key = 't1'), + 1, + (SELECT id FROM roles WHERE role_type = 0 AND tenant_id = (SELECT id FROM tenants WHERE key = 't1') LIMIT 1); + + -- User Credentials (bcrypt hashed password) + INSERT INTO user_credentials (user_id, auth_provider, password) + SELECT id, 'internal', '$2b$12$mNyM260paivMGoA0gThnkuYpBZ5V0yJHausASJtHINpMeUd9BJkwi' + FROM users + WHERE username = 'john.doe@example.com'; + + -- Update User with Auth Client + UPDATE users + SET auth_client_ids = ARRAY[ + (SELECT id FROM auth_clients WHERE client_id = 'temp_client')::integer + ] + WHERE username = 'john.doe@example.com'; + ``` + descrypted password is test123!@#, we stored it after encryption. ### Providers You can find documentation for some of the providers available in this service [here](./src/providers/README.md)