|
| 1 | +syntax = "proto3"; |
| 2 | + |
| 3 | +package construct.v1; |
| 4 | + |
| 5 | +import "buf/validate/validate.proto"; |
| 6 | +import "construct/v1/common.proto"; |
| 7 | +import "google/protobuf/duration.proto"; |
| 8 | +import "google/protobuf/timestamp.proto"; |
| 9 | + |
| 10 | +option go_package = "github.com/furisto/construct/api/go/v1"; |
| 11 | + |
| 12 | +// AuthService handles authentication operations including token management |
| 13 | +// and credential exchange flows. |
| 14 | +// |
| 15 | +// Token management operations (Create, List, Revoke) require admin privileges, |
| 16 | +// which are granted implicitly to connections over Unix sockets or explicitly |
| 17 | +// via tokens with admin scope. |
| 18 | +service AuthService { |
| 19 | + // CreateToken generates a new authentication token. |
| 20 | + // |
| 21 | + // The plaintext token is returned only once in the response and cannot be |
| 22 | + // retrieved again. |
| 23 | + rpc CreateToken(CreateTokenRequest) returns (CreateTokenResponse); |
| 24 | + |
| 25 | + // CreateSetupCode generates a short-lived, single-use code that can be |
| 26 | + // exchanged for a token via ExchangeSetupCode. |
| 27 | + // |
| 28 | + // Setup codes are designed for secure token distribution and expire quickly (default 15 minutes). |
| 29 | + rpc CreateSetupCode(CreateSetupCodeRequest) returns (CreateSetupCodeResponse); |
| 30 | + |
| 31 | + // ListTokens returns metadata about all tokens. |
| 32 | + // |
| 33 | + // Token values are never returned, only metadata such as name, creation time, |
| 34 | + // expiration, and last usage. |
| 35 | + rpc ListTokens(ListTokensRequest) returns (ListTokensResponse); |
| 36 | + |
| 37 | + // RevokeToken invalidates a token by name, preventing further use. |
| 38 | + rpc RevokeToken(RevokeTokenRequest) returns (RevokeTokenResponse); |
| 39 | + |
| 40 | + // ExchangeSetupCode exchanges a setup code for an authentication token. |
| 41 | + // |
| 42 | + // This is the only unauthenticated endpoint in the auth service. It allows |
| 43 | + // clients to obtain credentials using a short-lived setup code generated |
| 44 | + // by an admin via CreateSetupCode. |
| 45 | + // |
| 46 | + // Setup codes are single-use and automatically invalidated after successful |
| 47 | + // exchange or expiration. |
| 48 | + rpc ExchangeSetupCode(ExchangeSetupCodeRequest) returns (ExchangeSetupCodeResponse); |
| 49 | +} |
| 50 | + |
| 51 | +// CreateTokenRequest contains parameters for creating a new token. |
| 52 | +message CreateTokenRequest { |
| 53 | + // Human-readable name for the token. Must be unique. |
| 54 | + // Used for identification in listings and revocation. |
| 55 | + // Example: "macbook-thomas", "ci-pipeline" |
| 56 | + string name = 1 [ |
| 57 | + (buf.validate.field).string.min_len = 1, |
| 58 | + (buf.validate.field).string.max_len = 255 |
| 59 | + ]; |
| 60 | + |
| 61 | + // How long until the token expires. Default: 90 days. |
| 62 | + // Maximum allowed value is 365 days. |
| 63 | + optional google.protobuf.Duration expires_in = 2; |
| 64 | + |
| 65 | + // Optional description for the token's intended use. |
| 66 | + optional string description = 3 [(buf.validate.field).string.max_len = 2048]; |
| 67 | +} |
| 68 | + |
| 69 | +// CreateTokenResponse contains the newly created token. |
| 70 | +message CreateTokenResponse { |
| 71 | + // The plaintext token value. This is the only time this value is available; |
| 72 | + // it is not stored and cannot be retrieved again. |
| 73 | + // |
| 74 | + // Format: "ct_<base64url-encoded-random-bytes>" |
| 75 | + // The "ct_" prefix identifies Construct tokens in logs and configurations. |
| 76 | + string token = 1 [ |
| 77 | + (buf.validate.field).string.min_len = 1, |
| 78 | + (buf.validate.field).string.max_len = 255 |
| 79 | + ]; |
| 80 | + |
| 81 | + // When the token will expire. |
| 82 | + google.protobuf.Timestamp expires_at = 2 [(buf.validate.field).required = true]; |
| 83 | +} |
| 84 | + |
| 85 | +// CreateSetupCodeRequest contains parameters for creating a setup code. |
| 86 | +message CreateSetupCodeRequest { |
| 87 | + // Name for the token that will be created when the code is exchanged. |
| 88 | + // Must be unique at the time of exchange. |
| 89 | + string token_name = 1 [ |
| 90 | + (buf.validate.field).string.min_len = 1, |
| 91 | + (buf.validate.field).string.max_len = 255 |
| 92 | + ]; |
| 93 | + |
| 94 | + // How long until the setup code expires. Default: 5 minutes. |
| 95 | + // Maximum allowed value is 3 days. |
| 96 | + optional google.protobuf.Duration expires_in = 2; |
| 97 | + |
| 98 | + // How long the resulting token should be valid. Default: 90 days. |
| 99 | + optional google.protobuf.Duration token_expires_in = 3; |
| 100 | +} |
| 101 | + |
| 102 | +// CreateSetupCodeResponse contains the generated setup code. |
| 103 | +message CreateSetupCodeResponse { |
| 104 | + // Short, human-readable setup code. Format: "XXXX-XXXX" |
| 105 | + string setup_code = 1 [ |
| 106 | + (buf.validate.field).string.min_len = 1, |
| 107 | + (buf.validate.field).string.max_len = 9, |
| 108 | + (buf.validate.field).string.pattern = "^[A-Z0-9]{4}-[A-Z0-9]{4}$" |
| 109 | + ]; |
| 110 | + |
| 111 | + // When the setup code expires (typically 15 minutes). |
| 112 | + google.protobuf.Timestamp expires_at = 2 [(buf.validate.field).required = true]; |
| 113 | +} |
| 114 | + |
| 115 | +// ListTokensRequest contains optional filters for listing tokens. |
| 116 | +message ListTokensRequest { |
| 117 | + // Optional: filter by name prefix. |
| 118 | + string name_prefix = 1; |
| 119 | + |
| 120 | + // Optional: include expired tokens in results. Default: false. |
| 121 | + bool include_expired = 2; |
| 122 | +} |
| 123 | + |
| 124 | +// ListTokensResponse contains token metadata. |
| 125 | +message ListTokensResponse { |
| 126 | + repeated TokenInfo tokens = 1; |
| 127 | +} |
| 128 | + |
| 129 | +// TokenInfo contains metadata about a token |
| 130 | +message TokenInfo { |
| 131 | + // Unique identifier for the token. |
| 132 | + string id = 1 [(buf.validate.field).string.uuid = true]; |
| 133 | + |
| 134 | + // Human-readable name. |
| 135 | + string name = 2 [ |
| 136 | + (buf.validate.field).string.min_len = 1, |
| 137 | + (buf.validate.field).string.max_len = 255 |
| 138 | + ]; |
| 139 | + |
| 140 | + // Optional description. |
| 141 | + optional string description = 3 [(buf.validate.field).string.max_len = 2048]; |
| 142 | + |
| 143 | + // When the token was created. |
| 144 | + google.protobuf.Timestamp created_at = 4 [(buf.validate.field).required = true]; |
| 145 | + |
| 146 | + // When the token expires. |
| 147 | + google.protobuf.Timestamp expires_at = 5 [(buf.validate.field).required = true]; |
| 148 | + |
| 149 | + // Whether the token is currently valid (not expired, not revoked). |
| 150 | + bool is_active = 7 [(buf.validate.field).required = true]; |
| 151 | +} |
| 152 | + |
| 153 | +// RevokeTokenRequest identifies the token to revoke. |
| 154 | +message RevokeTokenRequest { |
| 155 | + // Name of the token to revoke. |
| 156 | + string id = 1 [(buf.validate.field).string.uuid = true]; |
| 157 | +} |
| 158 | + |
| 159 | +// RevokeTokenResponse confirms the revocation. |
| 160 | +message RevokeTokenResponse { |
| 161 | +} |
| 162 | + |
| 163 | +// ExchangeSetupCodeRequest contains the setup code to exchange. |
| 164 | +message ExchangeSetupCodeRequest { |
| 165 | + // Format: "XXXX-XXXX" |
| 166 | + string setup_code = 1 [ |
| 167 | + (buf.validate.field).string.min_len = 1, |
| 168 | + (buf.validate.field).string.max_len = 9, |
| 169 | + (buf.validate.field).string.pattern = "^[A-Z0-9]{4}-[A-Z0-9]{4}$" |
| 170 | + ]; |
| 171 | +} |
| 172 | + |
| 173 | +// ExchangeSetupCodeResponse contains the token issued in exchange. |
| 174 | +message ExchangeSetupCodeResponse { |
| 175 | + // The plaintext token value. |
| 176 | + string token = 1 [ |
| 177 | + (buf.validate.field).string.min_len = 1, |
| 178 | + (buf.validate.field).string.max_len = 255 |
| 179 | + ]; |
| 180 | + |
| 181 | + // When the token expires. |
| 182 | + google.protobuf.Timestamp expires_at = 2 [(buf.validate.field).required = true]; |
| 183 | + |
| 184 | + // The token name (as specified when the setup code was created). |
| 185 | + string name = 3 [ |
| 186 | + (buf.validate.field).string.min_len = 1, |
| 187 | + (buf.validate.field).string.max_len = 255 |
| 188 | + ]; |
| 189 | +} |
0 commit comments