mirror of
https://github.com/apricote/Listory.git
synced 2026-01-13 21:21:02 +00:00
feat(api): API tokens for authentication
Create and managed simple API tokens for access to the API from external tools.
This commit is contained in:
parent
eda89716ef
commit
8f7eebb806
15 changed files with 614 additions and 154 deletions
|
|
@ -3,9 +3,12 @@ import { ConfigService } from "@nestjs/config";
|
|||
import { JwtService } from "@nestjs/jwt";
|
||||
import { User } from "../users/user.entity";
|
||||
import { UsersService } from "../users/users.service";
|
||||
import { ApiToken } from "./api-token.entity";
|
||||
import { ApiTokenRepository } from "./api-token.repository";
|
||||
import { AuthSession } from "./auth-session.entity";
|
||||
import { AuthSessionRepository } from "./auth-session.repository";
|
||||
import { LoginDto } from "./dto/login.dto";
|
||||
import { randomBytes } from "crypto";
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
|
|
@ -16,7 +19,8 @@ export class AuthService {
|
|||
private readonly config: ConfigService,
|
||||
private readonly usersService: UsersService,
|
||||
private readonly jwtService: JwtService,
|
||||
private readonly authSessionRepository: AuthSessionRepository
|
||||
private readonly authSessionRepository: AuthSessionRepository,
|
||||
private readonly apiTokenRepository: ApiTokenRepository
|
||||
) {
|
||||
this.userFilter = this.config.get<string>("SPOTIFY_USER_FILTER");
|
||||
this.sessionExpirationTime = this.config.get<string>(
|
||||
|
|
@ -66,7 +70,7 @@ export class AuthService {
|
|||
*/
|
||||
private async createRefreshToken(
|
||||
session: AuthSession
|
||||
): Promise<{ refreshToken }> {
|
||||
): Promise<{ refreshToken: string }> {
|
||||
const payload = {
|
||||
sub: session.user.id,
|
||||
name: session.user.displayName,
|
||||
|
|
@ -81,7 +85,9 @@ export class AuthService {
|
|||
return { refreshToken: token };
|
||||
}
|
||||
|
||||
async createAccessToken(session: AuthSession): Promise<{ accessToken }> {
|
||||
async createAccessToken(
|
||||
session: AuthSession
|
||||
): Promise<{ accessToken: string }> {
|
||||
if (session.revokedAt) {
|
||||
throw new ForbiddenException("SessionIsRevoked");
|
||||
}
|
||||
|
|
@ -101,6 +107,41 @@ export class AuthService {
|
|||
return this.authSessionRepository.findOneBy({ id });
|
||||
}
|
||||
|
||||
async createApiToken(user: User, description: string): Promise<ApiToken> {
|
||||
console.log("createApiToken");
|
||||
const apiToken = this.apiTokenRepository.create();
|
||||
|
||||
apiToken.user = user;
|
||||
apiToken.description = description;
|
||||
|
||||
// TODO demagic 20
|
||||
const tokenBuffer = await new Promise<Buffer>((resolve, reject) =>
|
||||
randomBytes(20, (err, buf) => (err ? reject(err) : resolve(buf)))
|
||||
);
|
||||
apiToken.token = `lis${tokenBuffer.toString("hex")}`;
|
||||
|
||||
await this.apiTokenRepository.save(apiToken);
|
||||
|
||||
return apiToken;
|
||||
}
|
||||
|
||||
async listApiTokens(user: User): Promise<ApiToken[]> {
|
||||
return this.apiTokenRepository.scoped.byUser(user).getMany();
|
||||
}
|
||||
|
||||
async revokeApiToken(token: string): Promise<void> {
|
||||
const apiToken = await this.findApiToken(token);
|
||||
|
||||
apiToken.revokedAt = new Date();
|
||||
await this.apiTokenRepository.save(apiToken);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
async findApiToken(token: string): Promise<ApiToken> {
|
||||
return this.apiTokenRepository.findOneBy({ token });
|
||||
}
|
||||
|
||||
async findUser(id: string): Promise<User> {
|
||||
return this.usersService.findById(id);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue