diff --git a/authentik/core/api/tokens.py b/authentik/core/api/tokens.py index e8268ebe8..f8e14a2e8 100644 --- a/authentik/core/api/tokens.py +++ b/authentik/core/api/tokens.py @@ -2,6 +2,7 @@ from django.http.response import Http404 from drf_spectacular.utils import OpenApiResponse, extend_schema from rest_framework.decorators import action +from rest_framework.exceptions import ValidationError from rest_framework.fields import CharField from rest_framework.request import Request from rest_framework.response import Response @@ -22,6 +23,12 @@ class TokenSerializer(ManagedSerializer, ModelSerializer): user = UserSerializer(required=False) + def validate_intent(self, value: str) -> str: + """Ensure only API or App password tokens are created.""" + if value not in [TokenIntents.INTENT_API, TokenIntents.INTENT_APP_PASSWORD]: + raise ValidationError(f"Invalid intent {value}") + return value + class Meta: model = Token @@ -69,7 +76,6 @@ class TokenViewSet(UsedByMixin, ModelViewSet): def perform_create(self, serializer: TokenSerializer): serializer.save( user=self.request.user, - intent=TokenIntents.INTENT_API, expiring=self.request.user.attributes.get(USER_ATTRIBUTE_TOKEN_EXPIRING, True), ) diff --git a/web/src/pages/user-settings/UserSettingsPage.ts b/web/src/pages/user-settings/UserSettingsPage.ts index 88534871b..e7b627857 100644 --- a/web/src/pages/user-settings/UserSettingsPage.ts +++ b/web/src/pages/user-settings/UserSettingsPage.ts @@ -148,7 +148,7 @@ export class UserSettingsPage extends LitElement {
diff --git a/web/src/pages/user-settings/tokens/UserTokenForm.ts b/web/src/pages/user-settings/tokens/UserTokenForm.ts index 68a035d7a..3c4ffd4c2 100644 --- a/web/src/pages/user-settings/tokens/UserTokenForm.ts +++ b/web/src/pages/user-settings/tokens/UserTokenForm.ts @@ -1,6 +1,6 @@ -import { CoreApi, Token } from "@goauthentik/api"; +import { CoreApi, IntentEnum, Token } from "@goauthentik/api"; import { t } from "@lingui/macro"; -import { customElement } from "lit-element"; +import { customElement, property } from "lit-element"; import { html, TemplateResult } from "lit-html"; import { DEFAULT_CONFIG } from "../../../api/Config"; import { ifDefined } from "lit-html/directives/if-defined"; @@ -9,6 +9,9 @@ import { ModelForm } from "../../../elements/forms/ModelForm"; @customElement("ak-user-token-form") export class UserTokenForm extends ModelForm { + @property() + intent: IntentEnum = IntentEnum.Api; + loadInstance(pk: string): Promise { return new CoreApi(DEFAULT_CONFIG).coreTokensRetrieve({ identifier: pk, @@ -30,6 +33,7 @@ export class UserTokenForm extends ModelForm { tokenRequest: data, }); } else { + data.intent = this.intent; return new CoreApi(DEFAULT_CONFIG).coreTokensCreate({ tokenRequest: data, }); diff --git a/web/src/pages/user-settings/tokens/UserTokenList.ts b/web/src/pages/user-settings/tokens/UserTokenList.ts index 2b542d32b..76d743f42 100644 --- a/web/src/pages/user-settings/tokens/UserTokenList.ts +++ b/web/src/pages/user-settings/tokens/UserTokenList.ts @@ -10,7 +10,7 @@ import "../../../elements/buttons/Dropdown"; import "../../../elements/buttons/TokenCopyButton"; import { Table, TableColumn } from "../../../elements/table/Table"; import { PAGE_SIZE } from "../../../constants"; -import { CoreApi, Token } from "@goauthentik/api"; +import { CoreApi, IntentEnum, Token } from "@goauthentik/api"; import { DEFAULT_CONFIG } from "../../../api/Config"; import "./UserTokenForm"; @@ -48,8 +48,19 @@ export class UserTokenList extends Table { ${t`Create`} ${t`Create Token`} - - + + + + + ${t`Create`} + ${t`Create App password`} + + + ${super.renderToolbar()} `;