Skip to content

Access Tokens

Access Tokens — это токены для доступа к API от имени интеграций. Они используются для аутентификации внешних систем при взаимодействии с integ-core API.

Обзор

Access Tokens позволяют:

  • ✅ Генерировать токены для доступа к API
  • ✅ Управлять несколькими токенами
  • ✅ Отзывать токены при необходимости
  • ✅ Видеть информацию о токенах (название, дата создания)

Важно

Токен виден только один раз — при создании. После этого увидеть его повторно невозможно. Сохраните токен в безопасном месте!

Структура Access Token

typescript
interface IAccessToken {
	id: string; // UUID токена
	name: string; // Название токена
	token?: string; // Токен (только при создании)
	expiresAt?: string; // Дата истечения (опционально)
	createdAt: string; // Дата создания
}

Функциональность

Просмотр токенов

URL: /admin/access-tokens

Страница отображает таблицу всех созданных токенов с информацией:

  • Название токена
  • Дата создания
  • Дата истечения (если установлена)
  • Действия (удалить)

Пример кода:

typescript
@Component({
	selector: "app-access-tokens-list",
	standalone: true,
	imports: [MatTableModule, MatButtonModule, MatIconModule],
	templateUrl: "./access-tokens-list.component.html"
})
export class AccessTokensListComponent implements OnInit {
	private readonly accessTokensService = inject(AccessTokensService);

	tokens: IAccessToken[] = [];
	displayedColumns = ["name", "createdAt", "expiresAt", "actions"];

	ngOnInit() {
		this.loadTokens();
	}

	loadTokens() {
		this.accessTokensService.getAll().subscribe((tokens) => {
			this.tokens = tokens;
		});
	}

	deleteToken(id: string) {
		this.accessTokensService.delete(id).subscribe(() => {
			this.loadTokens();
		});
	}
}

Создание токена

При создании токена нужно указать только название.

Диалог создания:

typescript
@Component({
	selector: "app-access-token-create-dialog",
	standalone: true,
	imports: [MatDialogModule, ReactiveFormsModule, MatFormFieldModule],
	template: `
		<h2 mat-dialog-title>Создать Access Token</h2>
		<mat-dialog-content>
			<form [formGroup]="form">
				<mat-form-field>
					<mat-label>Название токена</mat-label>
					<input matInput formControlName="name" />
				</mat-form-field>
			</form>
		</mat-dialog-content>
		<mat-dialog-actions>
			<button matButton mat-dialog-close>Отмена</button>
			<button mat-raised-button color="primary" (click)="onSubmit()">Создать</button>
		</mat-dialog-actions>
	`
})
export class AccessTokenCreateDialogComponent {
	private readonly dialogRef = inject(MatDialogRef);

	form = new FormGroup({
		name: new FormControl("", Validators.required)
	});

	onSubmit() {
		if (this.form.valid) {
			this.dialogRef.close(this.form.value);
		}
	}
}

Открытие диалога и создание токена:

typescript
createToken() {
  const dialogRef = this.dialog.open(AccessTokenCreateDialogComponent, {
    width: '500px'
  });

  dialogRef.afterClosed().subscribe(result => {
    if (result) {
      this.accessTokensService.create(result).subscribe(response => {
        // response.token содержит полный токен
        this.showTokenDialog(response.token);
        this.loadTokens();
      });
    }
  });
}

Отображение созданного токена

После создания токена необходимо показать его пользователю:

typescript
showTokenDialog(token: string) {
  this.dialog.open(TokenDisplayDialogComponent, {
    width: '600px',
    data: { token },
    disableClose: true // Пользователь должен подтвердить копирование
  });
}

Компонент отображения токена:

typescript
@Component({
	selector: "app-token-display-dialog",
	standalone: true,
	imports: [MatDialogModule, MatButtonModule, MatIconModule],
	template: `
		<h2 mat-dialog-title>Access Token создан</h2>
		<mat-dialog-content>
			<div class="warning">⚠️ Скопируйте токен сейчас! Вы не сможете увидеть его снова.</div>

			<div class="token-container">
				<code>{{ data.token }}</code>
				<button mat-icon-button (click)="copyToken()">
					<mat-icon>content_copy</mat-icon>
				</button>
			</div>
		</mat-dialog-content>
		<mat-dialog-actions>
			<button mat-raised-button color="primary" (click)="confirm()">Я скопировал токен</button>
		</mat-dialog-actions>
	`
})
export class TokenDisplayDialogComponent {
	readonly data = inject(MAT_DIALOG_DATA);
	private readonly dialogRef = inject(MatDialogRef);

	copyToken() {
		navigator.clipboard.writeText(this.data.token);
		// Показать snackbar о успешном копировании
	}

	confirm() {
		this.dialogRef.close();
	}
}

Удаление токена

Удаление токена отзывает доступ:

typescript
deleteToken(tokenId: string) {
  const dialogRef = this.dialog.open(ConfirmDialogComponent, {
    data: {
      title: 'Удалить токен?',
      message: 'Это действие нельзя отменить. Все API запросы с этим токеном будут отклонены.'
    }
  });

  dialogRef.afterClosed().subscribe(confirmed => {
    if (confirmed) {
      this.accessTokensService.delete(tokenId).subscribe(() => {
        this.loadTokens();
      });
    }
  });
}

Использование токенов

В HTTP запросах

Токены используются для аутентификации API запросов:

bash
curl -X GET https://api.example.com/integrations \
  -H "Authorization: Bearer your-access-token-here"

В JavaScript/TypeScript

typescript
const headers = {
	"Authorization": `Bearer ${accessToken}`,
	"Content-Type": "application/json"
};

fetch("https://api.example.com/integrations", { headers })
	.then((response) => response.json())
	.then((data) => console.log(data));

В Angular HttpClient

typescript
const headers = new HttpHeaders({
	Authorization: `Bearer ${accessToken}`
});

this.http.get("/integrations", { headers }).subscribe((data) => console.log(data));

Безопасность

Best Practices

Что нужно делать:

  • Сохранять токены в безопасном месте (переменные окружения, secrets manager)
  • Использовать разные токены для разных сред (dev, staging, prod)
  • Регулярно ротировать токены
  • Удалять неиспользуемые токены
  • Использовать описательные названия (например, "Production API", "CI/CD Pipeline")

Чего НЕ делать:

  • Хранить токены в git репозитории
  • Передавать токены в URL параметрах
  • Использовать один токен для всех сред
  • Логировать токены в консоль или файлы

Ротация токенов

Рекомендуется периодически обновлять токены:

  1. Создать новый токен
  2. Обновить конфигурацию приложения
  3. Проверить работоспособность
  4. Удалить старый токен

API Endpoints

МетодEndpointОписание
GET/access-tokensСписок всех токенов
POST/access-tokensСоздать новый токен
DELETE/access-tokens/:idУдалить токен

INFO

Эндпоинт для обновления токена отсутствует. Вместо этого создайте новый токен и удалите старый.

Пример полного flow

typescript
// 1. Открыть диалог создания
const dialogRef = this.dialog.open(AccessTokenCreateDialogComponent);

// 2. Создать токен
dialogRef.afterClosed().subscribe((result) => {
	if (result) {
		this.accessTokensService.create(result).subscribe((response) => {
			// 3. Показать токен пользователю
			this.dialog.open(TokenDisplayDialogComponent, {
				data: { token: response.token },
				disableClose: true
			});

			// 4. Обновить список
			this.loadTokens();
		});
	}
});

Типичные ошибки

401 Unauthorized

Токен не валидный или удален. Создайте новый токен.

403 Forbidden

Токен валидный, но не имеет прав на выполнение операции.

Токен истек

Если установлена дата истечения и она прошла, создайте новый токен.

Мониторинг

Отслеживайте использование токенов через:

  • Audit logs
  • Последнее время использования (если реализовано)
  • Количество запросов (если реализовано)

Следующие шаги

SaaS Admin Documentation