From 5f5becad1b4f416179b019b8b046cd71146a78bd Mon Sep 17 00:00:00 2001 From: aman Date: Thu, 19 Feb 2026 11:39:28 +0530 Subject: [PATCH 1/5] feat: add CreateCurrentUserPersonalToken RPC --- raystack/frontier/v1beta1/frontier.proto | 27 ++++++++++++++++++++++++ raystack/frontier/v1beta1/models.proto | 27 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/raystack/frontier/v1beta1/frontier.proto b/raystack/frontier/v1beta1/frontier.proto index e2f26dca..b3e74dbd 100644 --- a/raystack/frontier/v1beta1/frontier.proto +++ b/raystack/frontier/v1beta1/frontier.proto @@ -1887,6 +1887,9 @@ service FrontierService { // Audit Records rpc CreateAuditRecord(CreateAuditRecordRequest) returns (CreateAuditRecordResponse) {} + + // Personal Access Token + rpc CreateCurrentUserPersonalToken(CreateCurrentUserPersonalTokenRequest) returns (CreateCurrentUserPersonalTokenResponse) {} } // Billing @@ -4256,3 +4259,27 @@ message CreateAuditRecordRequest { message CreateAuditRecordResponse { AuditRecord audit_record = 1; } + +message CreateCurrentUserPersonalTokenRequest { + // Machine-friendly identifier, unique per user per org + string name = 1 [ + (validate.rules).string.min_len = 1, + (google.api.field_behavior) = REQUIRED + ]; + // Human-friendly display name + string title = 2; + string org_id = 3 [ + (validate.rules).string.uuid = true, + (google.api.field_behavior) = REQUIRED + ]; + // Roles to scope the token to (e.g., ["app_organization_manager", "app_project_owner"]) + repeated string roles = 4 [(google.api.field_behavior) = REQUIRED]; + // For project-scoped roles: empty = all projects, non-empty = specific projects + repeated string project_ids = 5; + google.protobuf.Timestamp expires_at = 6 [(google.api.field_behavior) = REQUIRED]; + google.protobuf.Struct metadata = 7; +} + +message CreateCurrentUserPersonalTokenResponse { + PersonalAccessToken token = 1; +} diff --git a/raystack/frontier/v1beta1/models.proto b/raystack/frontier/v1beta1/models.proto index 53b146d8..3d076244 100644 --- a/raystack/frontier/v1beta1/models.proto +++ b/raystack/frontier/v1beta1/models.proto @@ -439,6 +439,33 @@ message ServiceUserToken { }]; } +message PersonalAccessToken { + string id = 1; + string name = 2; + string title = 3; + + // token will only be returned once as part of the create process + // this value is never persisted in the system so if lost, can't be recovered + string token = 4 [(google.api.field_behavior) = OUTPUT_ONLY]; + + google.protobuf.Struct metadata = 5; + + google.protobuf.Timestamp expires_at = 6 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "The time when the token expires.", + example: "\"2024-06-07T05:39:56.961Z\"" + }]; + + google.protobuf.Timestamp last_used_at = 7 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "The time when the token was last used.", + example: "\"2024-06-07T05:39:56.961Z\"" + }]; + + google.protobuf.Timestamp created_at = 8 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "The time when the token was created.", + example: "\"2023-06-07T05:39:56.961Z\"" + }]; +} + // JSON Web Key as specified in RFC 7517 message JSONWebKey { // Key Type. From da218b4f95fb554c281898de2931f8c79150d6ae Mon Sep 17 00:00:00 2001 From: aman Date: Thu, 19 Feb 2026 19:43:21 +0530 Subject: [PATCH 2/5] refactor: update PersonalAccessToken RPC --- raystack/frontier/v1beta1/frontier.proto | 19 ++++++++++--------- raystack/frontier/v1beta1/models.proto | 15 +++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/raystack/frontier/v1beta1/frontier.proto b/raystack/frontier/v1beta1/frontier.proto index b3e74dbd..1f99e0aa 100644 --- a/raystack/frontier/v1beta1/frontier.proto +++ b/raystack/frontier/v1beta1/frontier.proto @@ -4261,23 +4261,24 @@ message CreateAuditRecordResponse { } message CreateCurrentUserPersonalTokenRequest { - // Machine-friendly identifier, unique per user per org - string name = 1 [ + // Human-friendly display name, unique per user per org + string title = 1 [ (validate.rules).string.min_len = 1, (google.api.field_behavior) = REQUIRED ]; - // Human-friendly display name - string title = 2; - string org_id = 3 [ + string org_id = 2 [ (validate.rules).string.uuid = true, (google.api.field_behavior) = REQUIRED ]; // Roles to scope the token to (e.g., ["app_organization_manager", "app_project_owner"]) - repeated string roles = 4 [(google.api.field_behavior) = REQUIRED]; + repeated string roles = 3 [ + (google.api.field_behavior) = REQUIRED, + (validate.rules).repeated = {min_items: 1} + ]; // For project-scoped roles: empty = all projects, non-empty = specific projects - repeated string project_ids = 5; - google.protobuf.Timestamp expires_at = 6 [(google.api.field_behavior) = REQUIRED]; - google.protobuf.Struct metadata = 7; + repeated string project_ids = 4 [(validate.rules).repeated.items.string.uuid = true]; + google.protobuf.Timestamp expires_at = 5 [(google.api.field_behavior) = REQUIRED]; + google.protobuf.Struct metadata = 6; } message CreateCurrentUserPersonalTokenResponse { diff --git a/raystack/frontier/v1beta1/models.proto b/raystack/frontier/v1beta1/models.proto index 3d076244..414a784b 100644 --- a/raystack/frontier/v1beta1/models.proto +++ b/raystack/frontier/v1beta1/models.proto @@ -441,29 +441,28 @@ message ServiceUserToken { message PersonalAccessToken { string id = 1; - string name = 2; - string title = 3; + string title = 2; // token will only be returned once as part of the create process // this value is never persisted in the system so if lost, can't be recovered - string token = 4 [(google.api.field_behavior) = OUTPUT_ONLY]; + string token = 5 [(google.api.field_behavior) = OUTPUT_ONLY]; - google.protobuf.Struct metadata = 5; - - google.protobuf.Timestamp expires_at = 6 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + google.protobuf.Timestamp expires_at = 10 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "The time when the token expires.", example: "\"2024-06-07T05:39:56.961Z\"" }]; - google.protobuf.Timestamp last_used_at = 7 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + google.protobuf.Timestamp last_used_at = 11 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "The time when the token was last used.", example: "\"2024-06-07T05:39:56.961Z\"" }]; - google.protobuf.Timestamp created_at = 8 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + google.protobuf.Timestamp created_at = 12 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { description: "The time when the token was created.", example: "\"2023-06-07T05:39:56.961Z\"" }]; + + google.protobuf.Struct metadata = 20; } // JSON Web Key as specified in RFC 7517 From bed408edd7add32ab882bf1053692479b6028159 Mon Sep 17 00:00:00 2001 From: aman Date: Sat, 21 Feb 2026 19:49:07 +0530 Subject: [PATCH 3/5] feat: add user_id, org_id, and updated_at fields to PersonalAccessToken model --- raystack/frontier/v1beta1/models.proto | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/raystack/frontier/v1beta1/models.proto b/raystack/frontier/v1beta1/models.proto index 414a784b..668f120b 100644 --- a/raystack/frontier/v1beta1/models.proto +++ b/raystack/frontier/v1beta1/models.proto @@ -442,6 +442,8 @@ message ServiceUserToken { message PersonalAccessToken { string id = 1; string title = 2; + string user_id = 3; + string org_id = 4; // token will only be returned once as part of the create process // this value is never persisted in the system so if lost, can't be recovered @@ -462,6 +464,11 @@ message PersonalAccessToken { example: "\"2023-06-07T05:39:56.961Z\"" }]; + google.protobuf.Timestamp updated_at = 13 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "The time when the token was last updated.", + example: "\"2023-06-07T05:39:56.961Z\"" + }]; + google.protobuf.Struct metadata = 20; } From 08620d9bb9a3eb4f46adc2d828e61605e8503306 Mon Sep 17 00:00:00 2001 From: aman Date: Sat, 21 Feb 2026 20:05:34 +0530 Subject: [PATCH 4/5] add OUTPUT_ONLY field behavior to timestamp fields in PersonalAccessToken model --- raystack/frontier/v1beta1/models.proto | 33 ++++++++++++++++---------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/raystack/frontier/v1beta1/models.proto b/raystack/frontier/v1beta1/models.proto index 668f120b..90606998 100644 --- a/raystack/frontier/v1beta1/models.proto +++ b/raystack/frontier/v1beta1/models.proto @@ -454,20 +454,29 @@ message PersonalAccessToken { example: "\"2024-06-07T05:39:56.961Z\"" }]; - google.protobuf.Timestamp last_used_at = 11 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "The time when the token was last used.", - example: "\"2024-06-07T05:39:56.961Z\"" - }]; + google.protobuf.Timestamp last_used_at = 11 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "The time when the token was last used.", + example: "\"2024-06-07T05:39:56.961Z\"" + }, + (google.api.field_behavior) = OUTPUT_ONLY + ]; - google.protobuf.Timestamp created_at = 12 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "The time when the token was created.", - example: "\"2023-06-07T05:39:56.961Z\"" - }]; + google.protobuf.Timestamp created_at = 12 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "The time when the token was created.", + example: "\"2023-06-07T05:39:56.961Z\"" + }, + (google.api.field_behavior) = OUTPUT_ONLY + ]; - google.protobuf.Timestamp updated_at = 13 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "The time when the token was last updated.", - example: "\"2023-06-07T05:39:56.961Z\"" - }]; + google.protobuf.Timestamp updated_at = 13 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "The time when the token was last updated.", + example: "\"2023-06-07T05:39:56.961Z\"" + }, + (google.api.field_behavior) = OUTPUT_ONLY + ]; google.protobuf.Struct metadata = 20; } From 9eb3b9a5fb8baad182d0ba6c9ca167f4c467c5f2 Mon Sep 17 00:00:00 2001 From: aman Date: Tue, 24 Feb 2026 15:22:12 +0530 Subject: [PATCH 5/5] refactor: rename roles to role_ids in PersonalAccessToken model and add UUID validation --- raystack/frontier/v1beta1/frontier.proto | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/raystack/frontier/v1beta1/frontier.proto b/raystack/frontier/v1beta1/frontier.proto index 1f99e0aa..79c57205 100644 --- a/raystack/frontier/v1beta1/frontier.proto +++ b/raystack/frontier/v1beta1/frontier.proto @@ -4270,10 +4270,11 @@ message CreateCurrentUserPersonalTokenRequest { (validate.rules).string.uuid = true, (google.api.field_behavior) = REQUIRED ]; - // Roles to scope the token to (e.g., ["app_organization_manager", "app_project_owner"]) - repeated string roles = 3 [ + // Role ids to scope the token to + repeated string role_ids = 3 [ (google.api.field_behavior) = REQUIRED, - (validate.rules).repeated = {min_items: 1} + (validate.rules).repeated = {min_items: 1}, + (validate.rules).repeated.items.string.uuid = true ]; // For project-scoped roles: empty = all projects, non-empty = specific projects repeated string project_ids = 4 [(validate.rules).repeated.items.string.uuid = true];