mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-16 02:36:19 +00:00
Merge pull request #325 from SyncrowIOT/SP-1306-be-implement-client-credential-flow-that-accept-client-id-and-client-secret-from-3rd-party-applications-and-issue-o-auth-jwt-tokens
SP-1306-be-implement-client-credential-flow-that-accept-client-id-and-client-secret-from-3rd-party-applications-and-issue-o-auth-jwt-tokens
This commit is contained in:
@ -77,21 +77,28 @@ export class AuthService {
|
||||
return await this.sessionRepository.save(data);
|
||||
}
|
||||
|
||||
async getTokens(payload) {
|
||||
async getTokens(
|
||||
payload,
|
||||
isRefreshToken = true,
|
||||
accessTokenExpiry = '24h',
|
||||
refreshTokenExpiry = '30d',
|
||||
) {
|
||||
const [accessToken, refreshToken] = await Promise.all([
|
||||
this.jwtService.signAsync(payload, {
|
||||
secret: this.configService.get<string>('JWT_SECRET'),
|
||||
expiresIn: '24h',
|
||||
}),
|
||||
this.jwtService.signAsync(payload, {
|
||||
secret: this.configService.get<string>('JWT_SECRET'),
|
||||
expiresIn: '7d',
|
||||
expiresIn: accessTokenExpiry,
|
||||
}),
|
||||
isRefreshToken
|
||||
? this.jwtService.signAsync(payload, {
|
||||
secret: this.configService.get<string>('JWT_SECRET'),
|
||||
expiresIn: refreshTokenExpiry,
|
||||
})
|
||||
: null,
|
||||
]);
|
||||
|
||||
return {
|
||||
accessToken,
|
||||
refreshToken,
|
||||
...(isRefreshToken ? { refreshToken } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,17 @@
|
||||
export class ControllerRoute {
|
||||
static CLIENT = class {
|
||||
public static readonly ROUTE = 'client';
|
||||
|
||||
static ACTIONS = class {
|
||||
public static readonly REGISTER_NEW_CLIENT_SUMMARY =
|
||||
'Register a new client';
|
||||
public static readonly REGISTER_NEW_CLIENT_DESCRIPTION =
|
||||
'This endpoint registers a new client in the system.';
|
||||
public static readonly LOGIN_CLIENT_SUMMARY = 'Login a client';
|
||||
public static readonly LOGIN_CLIENT_DESCRIPTION =
|
||||
'This endpoint allows a client to log in to the system.';
|
||||
};
|
||||
};
|
||||
static PROJECT = class {
|
||||
public static readonly ROUTE = 'projects';
|
||||
static ACTIONS = class {
|
||||
|
@ -42,6 +42,7 @@ import { SpaceLinkEntity } from '../modules/space/entities/space-link.entity';
|
||||
import { SubspaceProductAllocationEntity } from '../modules/space/entities/subspace/subspace-product-allocation.entity';
|
||||
import { SubspaceEntity } from '../modules/space/entities/subspace/subspace.entity';
|
||||
import { TagEntity } from '../modules/space/entities/tag.entity';
|
||||
import { ClientEntity } from '../modules/client/entities';
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forRootAsync({
|
||||
@ -93,6 +94,7 @@ import { TagEntity } from '../modules/space/entities/tag.entity';
|
||||
SubspaceModelProductAllocationEntity,
|
||||
SpaceProductAllocationEntity,
|
||||
SubspaceProductAllocationEntity,
|
||||
ClientEntity,
|
||||
],
|
||||
namingStrategy: new SnakeNamingStrategy(),
|
||||
synchronize: Boolean(JSON.parse(configService.get('DB_SYNC'))),
|
||||
|
@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ClientEntity } from './entities';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([ClientEntity])],
|
||||
exports: [TypeOrmModule],
|
||||
})
|
||||
export class ClientRepositoryModule {}
|
20
libs/common/src/modules/client/dtos/client.dto.ts
Normal file
20
libs/common/src/modules/client/dtos/client.dto.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { IsArray, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class ClientDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public uuid: string;
|
||||
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public clientId: string;
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public clientSecret: string;
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
public redirectUri: string;
|
||||
@IsArray()
|
||||
@IsNotEmpty()
|
||||
public scopes: string[];
|
||||
}
|
1
libs/common/src/modules/client/dtos/index.ts
Normal file
1
libs/common/src/modules/client/dtos/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './client.dto';
|
46
libs/common/src/modules/client/entities/client.entity.ts
Normal file
46
libs/common/src/modules/client/entities/client.entity.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import { Entity, Column, Unique, OneToMany } from 'typeorm';
|
||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||
import { ClientDto } from '../dtos';
|
||||
import { UserEntity } from '../../user/entities';
|
||||
|
||||
@Entity({ name: 'clients' })
|
||||
@Unique(['clientId'])
|
||||
export class ClientEntity extends AbstractEntity<ClientDto> {
|
||||
@Column({
|
||||
type: 'uuid',
|
||||
default: () => 'gen_random_uuid()',
|
||||
nullable: false,
|
||||
})
|
||||
public uuid: string;
|
||||
|
||||
@Column({
|
||||
length: 255,
|
||||
nullable: false,
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column({
|
||||
length: 255,
|
||||
nullable: false,
|
||||
unique: true,
|
||||
})
|
||||
clientId: string;
|
||||
|
||||
@Column({
|
||||
length: 255,
|
||||
nullable: false,
|
||||
})
|
||||
clientSecret: string;
|
||||
|
||||
@Column({
|
||||
length: 255,
|
||||
nullable: false,
|
||||
})
|
||||
redirectUri: string;
|
||||
|
||||
@Column('simple-array')
|
||||
scopes: string[];
|
||||
|
||||
@OneToMany(() => UserEntity, (user) => user.client)
|
||||
users: UserEntity[];
|
||||
}
|
1
libs/common/src/modules/client/entities/index.ts
Normal file
1
libs/common/src/modules/client/entities/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './client.entity';
|
@ -0,0 +1,10 @@
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ClientEntity } from '../entities';
|
||||
|
||||
@Injectable()
|
||||
export class ClientRepository extends Repository<ClientEntity> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(ClientEntity, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
1
libs/common/src/modules/client/repositories/index.ts
Normal file
1
libs/common/src/modules/client/repositories/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './client.repository';
|
@ -29,6 +29,7 @@ import { VisitorPasswordEntity } from '../../visitor-password/entities';
|
||||
import { InviteUserEntity } from '../../Invite-user/entities';
|
||||
import { ProjectEntity } from '../../project/entities';
|
||||
import { SpaceEntity } from '../../space/entities/space.entity';
|
||||
import { ClientEntity } from '../../client/entities';
|
||||
|
||||
@Entity({ name: 'user' })
|
||||
export class UserEntity extends AbstractEntity<UserDto> {
|
||||
@ -143,6 +144,13 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
||||
})
|
||||
@JoinColumn({ name: 'project_uuid' })
|
||||
public project: ProjectEntity;
|
||||
|
||||
@ManyToOne(() => ClientEntity, (client) => client.users, {
|
||||
nullable: true,
|
||||
})
|
||||
@JoinColumn({ name: 'client_uuid' })
|
||||
public client: ClientEntity;
|
||||
|
||||
constructor(partial: Partial<UserEntity>) {
|
||||
super();
|
||||
Object.assign(this, partial);
|
||||
|
Reference in New Issue
Block a user