Compare commits

...

3 Commits
v0.2.0 ... main

Author SHA1 Message Date
Michael Netshipise 369d4d5580 admin: GetUsersData — system-token user lookup (id + name only)
A new system-token-authed admin RPC: resolves user ids to display names with NO
PII (email/phone), authorized by a shared system token alone (no actor). Lets
internal services label "who did this" (e.g. CMS content history) without the
end-user's credentials and without a vector to harvest contact info. Adds the
proto messages + the AdminClient::get_users_data wrapper.
2026-06-14 06:58:23 +02:00
Michael Netshipise 30876f17f2 verify_api_key in all three languages + Rust key-management wrappers — v0.2.2
The service-credential seam: VerifyApiKey returns the key's owning
service user + roles (same AuthenticationResponse shape), so consumers
build their Ctx identically to a session. Cached ~60s per key,
namespaced away from token cache entries. Rust additionally wraps
CreateApiKey/ListApiKeys/RevokeApiKey. Versioning note: client patch
releases may lead the server within a minor line when only exposing
existing server surface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 22:46:54 +02:00
Michael Netshipise 78c6e1a0d9 Add admin surface (AuthAdminService) + scoped token verification — v0.2.1
- Vendor st-peter-admin.proto (sync-protos.sh now syncs both; health.proto
  remains excluded). Stubs generated for Rust/Go/TS.
- Rust: AdminClient — actor-credentialed wrappers over the admin surface
  (assign_role/unassign_role with target + expiry, get_assignable_roles/
  targets, get_user_with_roles, search_users, get_users_by_role,
  create/delete/restore_user, get/clear_user_sessions), Actor type,
  Error::Rejected for success=false responses, raw() escape hatch.
- All languages: verify_token_scoped(token, scopes) — roles filtered by
  role_scopes (e.g. ["cms"]); cache keyed per (token, scopes) so filtered
  and unfiltered verifications never share an entry. verify_token now
  delegates to the scoped variant with no filter.
- README: shared-vs-local role rule replaces 'authorization local';
  admin surface documented; examples bumped.

Tagged v0.2.1 in lockstep with the st-peter server line.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 21:00:41 +02:00
16 changed files with 17839 additions and 39 deletions

View File

@ -12,39 +12,57 @@ server**:
| Go | `go/` | `git.awesomike.com/pub/st-peter-client/go` (module) |
| TypeScript | `ts/` | `@st-peter/client` (npm) |
The `.proto` file in `proto/` is a **vendored copy**; the st-peter server repo
is the source of truth. `scripts/sync-protos.sh` refreshes it and keeps
`VERSION` aligned with the server. Only the **auth** surface is vendored —
services authenticate users; they do not administer st-peter.
The `.proto` files in `proto/` are **vendored copies**; the st-peter server repo
is the source of truth. `scripts/sync-protos.sh` refreshes them and keeps
`VERSION` aligned with the server. Two surfaces are vendored: **auth**
(authentication + roles-with-verification) and **admin** (`AuthAdminService` —
user administration and **targeted-role** management, actor-credentialed:
aura-users authorizes the acting admin by its own assignability rules).
## Versioning
Every release is tagged at the **same version as the st-peter server** it
targets (see `VERSION`). A client tagged `v0.2.0` speaks the wire contract of
st-peter `v0.2.0`. The gRPC wire format is backward-compatible across patch
targets (see `VERSION`). A client tagged `v0.2.x` speaks the wire contract of
st-peter `v0.2.1`+ (client patch releases may lead the server within a minor line when they only expose existing server surface — v0.2.2 adds API-key wrappers). The gRPC wire format is backward-compatible across patch
releases (field numbers and enum integer values are stable), so a client one
patch behind a server generally interoperates — but match versions for new
surface.
## Design: authentication central, authorization local
## Design: authentication central; roles shared-vs-local
st-peter answers *who is this token?* — every client returns the verified
identity plus the user's **platform** roles, with a ~60s token-verify cache.
What that identity may do inside a consuming service (media roles, CMS
roles, …) is that service's own concern: keep a local roles table keyed by
the st-peter `user_id` **by value** (no cross-DB FK) and map permissions
there. These clients deliberately ship no session/permission types.
identity plus the user's roles, with a ~60s token-verify cache. The role
rule: **roles shared among microservices live in st-peter as targeted roles**
(role + scope + opaque `target_id` + optional expiry — e.g. `cms-admin`
targeted at an organization), granted/revoked through the admin surface;
**truly service-local roles stay inside that service** (a local table keyed
by the st-peter `user_id` by value, no cross-DB FK). Either way, the
authorization *semantics* — what a role means, permission mapping — are the
consuming service's own concern: these clients deliberately ship no
session/permission types.
The wrapper surface is the same in all three languages:
- `connect(target)` — lazy dial; failures surface on the first call
- `verify_token(token)` — verified user + platform roles, cached ~60s
- `verify_token(token)` — verified user + all roles, cached ~60s
- `verify_token_scoped(token, scopes)` — roles filtered to the caller's
scope(s) (e.g. `["cms"]`); cached per `(token, scopes)`
- `login(identifier, password)``Authenticated | TwoFactor | Failed`
- `verify_two_factor(two_factor_id, code)` — complete an OTP challenge
- `lookup_user(actor_id, actor_token, identifier)` — resolve a user by
email/phone/handle (for local role-grant flows)
email/phone/handle
- `verify_api_key(key)` — service-credential path: the key's owning service
user + roles (cached); Rust adds `create_api_key` / `list_api_keys` /
`revoke_api_key` management wrappers
- `bearer(...)` helper + the shared `aura_session` cookie name
The **admin surface** (`AdminClient` — Rust first; Go/TS expose the generated
stubs): `assign_role` / `unassign_role` (targeted + time-bound grants),
`get_assignable_roles` / `get_assignable_targets`, `get_user_with_roles`,
`search_users`, `get_users_by_role`, `create_user` / `delete_user` /
`restore_user`, `get_user_sessions` / `clear_user_sessions` — every call
carries an `Actor { user_id, token }`.
## Layout
```
@ -72,17 +90,17 @@ Then tag at `v$(cat VERSION)`.
Rust (`Cargo.toml`):
```toml
st-peter-client = { git = "https://git.awesomike.com/pub/st-peter-client.git", tag = "v0.2.0" }
st-peter-client = { git = "https://git.awesomike.com/pub/st-peter-client.git", tag = "v0.2.2" }
```
Go:
```bash
go get git.awesomike.com/pub/st-peter-client/go@v0.2.0
go get git.awesomike.com/pub/st-peter-client/go@v0.2.2
```
TypeScript (`package.json`):
```json
"@st-peter/client": "git+https://git.awesomike.com/pub/st-peter-client.git#v0.2.0"
"@st-peter/client": "git+https://git.awesomike.com/pub/st-peter-client.git#v0.2.2"
```

View File

@ -1 +1 @@
0.2.0
0.2.3

View File

@ -75,10 +75,18 @@ func Connect(target string, opts ...grpc.DialOption) (*AuthClient, error) {
func (c *AuthClient) Close() error { return c.conn.Close() }
// VerifyToken verifies a session token, returning the authenticated user
// (+ platform roles). Verifications are cached ~60s to avoid a gRPC
// with all of their roles. Verifications are cached ~60s to avoid a gRPC
// round-trip per request. Returns ErrUnauthorized on a bad token.
func (c *AuthClient) VerifyToken(ctx context.Context, token string) (*pb.AuthenticatedUser, error) {
key := tokenHash(token)
return c.VerifyTokenScoped(ctx, token, nil)
}
// VerifyTokenScoped verifies a session token, returning roles filtered to
// the given scopes (e.g. []string{"cms"}) — each service pulls only its own
// scope's roles. Nil/empty scopes = all roles. Cached ~60s per
// (token, scopes) combination.
func (c *AuthClient) VerifyTokenScoped(ctx context.Context, token string, roleScopes []string) (*pb.AuthenticatedUser, error) {
key := cacheKey(token, roleScopes)
c.mu.RLock()
if e, ok := c.cache[key]; ok && time.Since(e.at) < authCacheTTL {
@ -89,7 +97,8 @@ func (c *AuthClient) VerifyToken(ctx context.Context, token string) (*pb.Authent
resp, err := c.svc.VerifyToken(ctx, &pb.VerifyTokenRequest{
Token: token,
IncludeUserRoles: true, // platform roles; service roles stay local
IncludeUserRoles: true,
RoleScopes: roleScopes,
})
if err != nil {
return nil, err
@ -107,6 +116,34 @@ func (c *AuthClient) VerifyToken(ctx context.Context, token string) (*pb.Authent
return user, nil
}
// VerifyApiKey verifies a service API key, returning the key's OWNING
// SERVICE USER plus that user's roles — consumers build their context
// identically to a session. Cached ~60s per key, like tokens.
func (c *AuthClient) VerifyApiKey(ctx context.Context, apiKey string) (*pb.AuthenticatedUser, error) {
key := cacheKey(apiKey, []string{"#api-key"}) // namespaced away from tokens
c.mu.RLock()
if e, ok := c.cache[key]; ok && time.Since(e.at) < authCacheTTL {
c.mu.RUnlock()
return e.user, nil
}
c.mu.RUnlock()
resp, err := c.svc.VerifyApiKey(ctx, &pb.VerifyApiKeyRequest{ApiKey: apiKey})
if err != nil {
return nil, err
}
if !resp.GetSuccess() || resp.GetAuthenticatedUser() == nil {
return nil, ErrUnauthorized
}
user := resp.GetAuthenticatedUser()
c.mu.Lock()
c.cache[key] = cacheEntry{user: user, at: time.Now()}
c.mu.Unlock()
return user, nil
}
// LoginOutcome is the result of Login / VerifyTwoFactor. Exactly one of the
// three fields is set.
type LoginOutcome struct {
@ -192,10 +229,15 @@ func Bearer(authorization string) (string, bool) {
return strings.TrimSpace(tok), true
}
// tokenHash is a fast (non-cryptographic) hash of the token, used only as
// the cache key.
func tokenHash(token string) uint64 {
// cacheKey is a fast (non-cryptographic) hash of (token, scope filter), used
// only as the cache key — the same token verified under different scope
// filters returns different role sets and must not share an entry.
func cacheKey(token string, roleScopes []string) uint64 {
h := fnv.New64a()
_, _ = h.Write([]byte(token))
for _, s := range roleScopes {
_, _ = h.Write([]byte{0})
_, _ = h.Write([]byte(s))
}
return h.Sum64()
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,995 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.6.2
// - protoc v7.34.1
// source: st-peter-admin.proto
package auth_admin_service
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.64.0 or later.
const _ = grpc.SupportPackageIsVersion9
const (
AuthAdminService_GetUser_FullMethodName = "/st_peter.admin.AuthAdminService/GetUser"
AuthAdminService_GetUsers_FullMethodName = "/st_peter.admin.AuthAdminService/GetUsers"
AuthAdminService_GetUsersByUsernames_FullMethodName = "/st_peter.admin.AuthAdminService/GetUsersByUsernames"
AuthAdminService_DeleteUser_FullMethodName = "/st_peter.admin.AuthAdminService/DeleteUser"
AuthAdminService_RestoreUser_FullMethodName = "/st_peter.admin.AuthAdminService/RestoreUser"
AuthAdminService_AssignRoleToUser_FullMethodName = "/st_peter.admin.AuthAdminService/AssignRoleToUser"
AuthAdminService_UnassignRoleFromUser_FullMethodName = "/st_peter.admin.AuthAdminService/UnassignRoleFromUser"
AuthAdminService_GetRoleDetails_FullMethodName = "/st_peter.admin.AuthAdminService/GetRoleDetails"
AuthAdminService_GetRole_FullMethodName = "/st_peter.admin.AuthAdminService/GetRole"
AuthAdminService_GetUserRole_FullMethodName = "/st_peter.admin.AuthAdminService/GetUserRole"
AuthAdminService_SearchUsers_FullMethodName = "/st_peter.admin.AuthAdminService/SearchUsers"
AuthAdminService_CountUsers_FullMethodName = "/st_peter.admin.AuthAdminService/CountUsers"
AuthAdminService_SearchRoles_FullMethodName = "/st_peter.admin.AuthAdminService/SearchRoles"
AuthAdminService_GetRoleScopes_FullMethodName = "/st_peter.admin.AuthAdminService/GetRoleScopes"
AuthAdminService_GetUserWithRoles_FullMethodName = "/st_peter.admin.AuthAdminService/GetUserWithRoles"
AuthAdminService_GetAssignableRoles_FullMethodName = "/st_peter.admin.AuthAdminService/GetAssignableRoles"
AuthAdminService_UpdateUserInfo_FullMethodName = "/st_peter.admin.AuthAdminService/UpdateUserInfo"
AuthAdminService_GetScopeAncestors_FullMethodName = "/st_peter.admin.AuthAdminService/GetScopeAncestors"
AuthAdminService_GetScopeDescendants_FullMethodName = "/st_peter.admin.AuthAdminService/GetScopeDescendants"
AuthAdminService_GetAssignableTargets_FullMethodName = "/st_peter.admin.AuthAdminService/GetAssignableTargets"
AuthAdminService_GetUsersByRole_FullMethodName = "/st_peter.admin.AuthAdminService/GetUsersByRole"
AuthAdminService_CreateUser_FullMethodName = "/st_peter.admin.AuthAdminService/CreateUser"
AuthAdminService_GetUserSessions_FullMethodName = "/st_peter.admin.AuthAdminService/GetUserSessions"
AuthAdminService_ClearUserSessions_FullMethodName = "/st_peter.admin.AuthAdminService/ClearUserSessions"
)
// AuthAdminServiceClient is the client API for AuthAdminService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type AuthAdminServiceClient interface {
GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*UserResponse, error)
GetUsers(ctx context.Context, in *GetUsersRequest, opts ...grpc.CallOption) (*UsersResponse, error)
GetUsersByUsernames(ctx context.Context, in *GetUsersByUsernamesRequest, opts ...grpc.CallOption) (*UsersResponse, error)
DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*OperationResponse, error)
RestoreUser(ctx context.Context, in *RestoreUserRequest, opts ...grpc.CallOption) (*OperationResponse, error)
AssignRoleToUser(ctx context.Context, in *AssignRoleRequest, opts ...grpc.CallOption) (*GetUserWithRolesResponse, error)
UnassignRoleFromUser(ctx context.Context, in *UnassignRoleRequest, opts ...grpc.CallOption) (*GetUserWithRolesResponse, error)
GetRoleDetails(ctx context.Context, in *GetRoleDetailsRequest, opts ...grpc.CallOption) (*GetRoleDetailsResponse, error)
GetRole(ctx context.Context, in *GetRoleRequest, opts ...grpc.CallOption) (*GetRoleResponse, error)
GetUserRole(ctx context.Context, in *GetUserRoleRequest, opts ...grpc.CallOption) (*GetUserRoleResponse, error)
SearchUsers(ctx context.Context, in *SearchUsersRequest, opts ...grpc.CallOption) (*SearchUsersResponse, error)
CountUsers(ctx context.Context, in *CountUsersRequest, opts ...grpc.CallOption) (*CountUsersResponse, error)
SearchRoles(ctx context.Context, in *SearchRolesRequest, opts ...grpc.CallOption) (*SearchRolesResponse, error)
GetRoleScopes(ctx context.Context, in *GetRoleScopesRequest, opts ...grpc.CallOption) (*GetRoleScopesResponse, error)
GetUserWithRoles(ctx context.Context, in *GetUserWithRolesRequest, opts ...grpc.CallOption) (*GetUserWithRolesResponse, error)
GetAssignableRoles(ctx context.Context, in *GetAssignableRolesRequest, opts ...grpc.CallOption) (*GetAssignableRolesResponse, error)
UpdateUserInfo(ctx context.Context, in *UpdateUserInfoRequest, opts ...grpc.CallOption) (*UpdateUserInfoResponse, error)
GetScopeAncestors(ctx context.Context, in *GetScopeAncestorsRequest, opts ...grpc.CallOption) (*GetScopeAncestorsResponse, error)
GetScopeDescendants(ctx context.Context, in *GetScopeDescendantsRequest, opts ...grpc.CallOption) (*GetScopeDescendantsResponse, error)
GetAssignableTargets(ctx context.Context, in *GetAssignableTargetsRequest, opts ...grpc.CallOption) (*GetAssignableTargetsResponse, error)
GetUsersByRole(ctx context.Context, in *GetUsersByRoleRequest, opts ...grpc.CallOption) (*GetUsersByRoleResponse, error)
CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error)
GetUserSessions(ctx context.Context, in *GetUserSessionsRequest, opts ...grpc.CallOption) (*GetUserSessionsResponse, error)
ClearUserSessions(ctx context.Context, in *ClearUserSessionsRequest, opts ...grpc.CallOption) (*ClearUserSessionsResponse, error)
}
type authAdminServiceClient struct {
cc grpc.ClientConnInterface
}
func NewAuthAdminServiceClient(cc grpc.ClientConnInterface) AuthAdminServiceClient {
return &authAdminServiceClient{cc}
}
func (c *authAdminServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*UserResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UserResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetUser_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetUsers(ctx context.Context, in *GetUsersRequest, opts ...grpc.CallOption) (*UsersResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UsersResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetUsers_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetUsersByUsernames(ctx context.Context, in *GetUsersByUsernamesRequest, opts ...grpc.CallOption) (*UsersResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UsersResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetUsersByUsernames_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) DeleteUser(ctx context.Context, in *DeleteUserRequest, opts ...grpc.CallOption) (*OperationResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(OperationResponse)
err := c.cc.Invoke(ctx, AuthAdminService_DeleteUser_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) RestoreUser(ctx context.Context, in *RestoreUserRequest, opts ...grpc.CallOption) (*OperationResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(OperationResponse)
err := c.cc.Invoke(ctx, AuthAdminService_RestoreUser_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) AssignRoleToUser(ctx context.Context, in *AssignRoleRequest, opts ...grpc.CallOption) (*GetUserWithRolesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetUserWithRolesResponse)
err := c.cc.Invoke(ctx, AuthAdminService_AssignRoleToUser_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) UnassignRoleFromUser(ctx context.Context, in *UnassignRoleRequest, opts ...grpc.CallOption) (*GetUserWithRolesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetUserWithRolesResponse)
err := c.cc.Invoke(ctx, AuthAdminService_UnassignRoleFromUser_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetRoleDetails(ctx context.Context, in *GetRoleDetailsRequest, opts ...grpc.CallOption) (*GetRoleDetailsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetRoleDetailsResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetRoleDetails_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetRole(ctx context.Context, in *GetRoleRequest, opts ...grpc.CallOption) (*GetRoleResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetRoleResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetRole_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetUserRole(ctx context.Context, in *GetUserRoleRequest, opts ...grpc.CallOption) (*GetUserRoleResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetUserRoleResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetUserRole_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) SearchUsers(ctx context.Context, in *SearchUsersRequest, opts ...grpc.CallOption) (*SearchUsersResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(SearchUsersResponse)
err := c.cc.Invoke(ctx, AuthAdminService_SearchUsers_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) CountUsers(ctx context.Context, in *CountUsersRequest, opts ...grpc.CallOption) (*CountUsersResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CountUsersResponse)
err := c.cc.Invoke(ctx, AuthAdminService_CountUsers_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) SearchRoles(ctx context.Context, in *SearchRolesRequest, opts ...grpc.CallOption) (*SearchRolesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(SearchRolesResponse)
err := c.cc.Invoke(ctx, AuthAdminService_SearchRoles_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetRoleScopes(ctx context.Context, in *GetRoleScopesRequest, opts ...grpc.CallOption) (*GetRoleScopesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetRoleScopesResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetRoleScopes_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetUserWithRoles(ctx context.Context, in *GetUserWithRolesRequest, opts ...grpc.CallOption) (*GetUserWithRolesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetUserWithRolesResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetUserWithRoles_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetAssignableRoles(ctx context.Context, in *GetAssignableRolesRequest, opts ...grpc.CallOption) (*GetAssignableRolesResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetAssignableRolesResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetAssignableRoles_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) UpdateUserInfo(ctx context.Context, in *UpdateUserInfoRequest, opts ...grpc.CallOption) (*UpdateUserInfoResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(UpdateUserInfoResponse)
err := c.cc.Invoke(ctx, AuthAdminService_UpdateUserInfo_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetScopeAncestors(ctx context.Context, in *GetScopeAncestorsRequest, opts ...grpc.CallOption) (*GetScopeAncestorsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetScopeAncestorsResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetScopeAncestors_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetScopeDescendants(ctx context.Context, in *GetScopeDescendantsRequest, opts ...grpc.CallOption) (*GetScopeDescendantsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetScopeDescendantsResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetScopeDescendants_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetAssignableTargets(ctx context.Context, in *GetAssignableTargetsRequest, opts ...grpc.CallOption) (*GetAssignableTargetsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetAssignableTargetsResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetAssignableTargets_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetUsersByRole(ctx context.Context, in *GetUsersByRoleRequest, opts ...grpc.CallOption) (*GetUsersByRoleResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetUsersByRoleResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetUsersByRole_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) CreateUser(ctx context.Context, in *CreateUserRequest, opts ...grpc.CallOption) (*CreateUserResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(CreateUserResponse)
err := c.cc.Invoke(ctx, AuthAdminService_CreateUser_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) GetUserSessions(ctx context.Context, in *GetUserSessionsRequest, opts ...grpc.CallOption) (*GetUserSessionsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(GetUserSessionsResponse)
err := c.cc.Invoke(ctx, AuthAdminService_GetUserSessions_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *authAdminServiceClient) ClearUserSessions(ctx context.Context, in *ClearUserSessionsRequest, opts ...grpc.CallOption) (*ClearUserSessionsResponse, error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
out := new(ClearUserSessionsResponse)
err := c.cc.Invoke(ctx, AuthAdminService_ClearUserSessions_FullMethodName, in, out, cOpts...)
if err != nil {
return nil, err
}
return out, nil
}
// AuthAdminServiceServer is the server API for AuthAdminService service.
// All implementations must embed UnimplementedAuthAdminServiceServer
// for forward compatibility.
type AuthAdminServiceServer interface {
GetUser(context.Context, *GetUserRequest) (*UserResponse, error)
GetUsers(context.Context, *GetUsersRequest) (*UsersResponse, error)
GetUsersByUsernames(context.Context, *GetUsersByUsernamesRequest) (*UsersResponse, error)
DeleteUser(context.Context, *DeleteUserRequest) (*OperationResponse, error)
RestoreUser(context.Context, *RestoreUserRequest) (*OperationResponse, error)
AssignRoleToUser(context.Context, *AssignRoleRequest) (*GetUserWithRolesResponse, error)
UnassignRoleFromUser(context.Context, *UnassignRoleRequest) (*GetUserWithRolesResponse, error)
GetRoleDetails(context.Context, *GetRoleDetailsRequest) (*GetRoleDetailsResponse, error)
GetRole(context.Context, *GetRoleRequest) (*GetRoleResponse, error)
GetUserRole(context.Context, *GetUserRoleRequest) (*GetUserRoleResponse, error)
SearchUsers(context.Context, *SearchUsersRequest) (*SearchUsersResponse, error)
CountUsers(context.Context, *CountUsersRequest) (*CountUsersResponse, error)
SearchRoles(context.Context, *SearchRolesRequest) (*SearchRolesResponse, error)
GetRoleScopes(context.Context, *GetRoleScopesRequest) (*GetRoleScopesResponse, error)
GetUserWithRoles(context.Context, *GetUserWithRolesRequest) (*GetUserWithRolesResponse, error)
GetAssignableRoles(context.Context, *GetAssignableRolesRequest) (*GetAssignableRolesResponse, error)
UpdateUserInfo(context.Context, *UpdateUserInfoRequest) (*UpdateUserInfoResponse, error)
GetScopeAncestors(context.Context, *GetScopeAncestorsRequest) (*GetScopeAncestorsResponse, error)
GetScopeDescendants(context.Context, *GetScopeDescendantsRequest) (*GetScopeDescendantsResponse, error)
GetAssignableTargets(context.Context, *GetAssignableTargetsRequest) (*GetAssignableTargetsResponse, error)
GetUsersByRole(context.Context, *GetUsersByRoleRequest) (*GetUsersByRoleResponse, error)
CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error)
GetUserSessions(context.Context, *GetUserSessionsRequest) (*GetUserSessionsResponse, error)
ClearUserSessions(context.Context, *ClearUserSessionsRequest) (*ClearUserSessionsResponse, error)
mustEmbedUnimplementedAuthAdminServiceServer()
}
// UnimplementedAuthAdminServiceServer must be embedded to have
// forward compatible implementations.
//
// NOTE: this should be embedded by value instead of pointer to avoid a nil
// pointer dereference when methods are called.
type UnimplementedAuthAdminServiceServer struct{}
func (UnimplementedAuthAdminServiceServer) GetUser(context.Context, *GetUserRequest) (*UserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUser not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetUsers(context.Context, *GetUsersRequest) (*UsersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUsers not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetUsersByUsernames(context.Context, *GetUsersByUsernamesRequest) (*UsersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUsersByUsernames not implemented")
}
func (UnimplementedAuthAdminServiceServer) DeleteUser(context.Context, *DeleteUserRequest) (*OperationResponse, error) {
return nil, status.Error(codes.Unimplemented, "method DeleteUser not implemented")
}
func (UnimplementedAuthAdminServiceServer) RestoreUser(context.Context, *RestoreUserRequest) (*OperationResponse, error) {
return nil, status.Error(codes.Unimplemented, "method RestoreUser not implemented")
}
func (UnimplementedAuthAdminServiceServer) AssignRoleToUser(context.Context, *AssignRoleRequest) (*GetUserWithRolesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method AssignRoleToUser not implemented")
}
func (UnimplementedAuthAdminServiceServer) UnassignRoleFromUser(context.Context, *UnassignRoleRequest) (*GetUserWithRolesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UnassignRoleFromUser not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetRoleDetails(context.Context, *GetRoleDetailsRequest) (*GetRoleDetailsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoleDetails not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetRole(context.Context, *GetRoleRequest) (*GetRoleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRole not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetUserRole(context.Context, *GetUserRoleRequest) (*GetUserRoleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUserRole not implemented")
}
func (UnimplementedAuthAdminServiceServer) SearchUsers(context.Context, *SearchUsersRequest) (*SearchUsersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SearchUsers not implemented")
}
func (UnimplementedAuthAdminServiceServer) CountUsers(context.Context, *CountUsersRequest) (*CountUsersResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CountUsers not implemented")
}
func (UnimplementedAuthAdminServiceServer) SearchRoles(context.Context, *SearchRolesRequest) (*SearchRolesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method SearchRoles not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetRoleScopes(context.Context, *GetRoleScopesRequest) (*GetRoleScopesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetRoleScopes not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetUserWithRoles(context.Context, *GetUserWithRolesRequest) (*GetUserWithRolesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUserWithRoles not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetAssignableRoles(context.Context, *GetAssignableRolesRequest) (*GetAssignableRolesResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetAssignableRoles not implemented")
}
func (UnimplementedAuthAdminServiceServer) UpdateUserInfo(context.Context, *UpdateUserInfoRequest) (*UpdateUserInfoResponse, error) {
return nil, status.Error(codes.Unimplemented, "method UpdateUserInfo not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetScopeAncestors(context.Context, *GetScopeAncestorsRequest) (*GetScopeAncestorsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetScopeAncestors not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetScopeDescendants(context.Context, *GetScopeDescendantsRequest) (*GetScopeDescendantsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetScopeDescendants not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetAssignableTargets(context.Context, *GetAssignableTargetsRequest) (*GetAssignableTargetsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetAssignableTargets not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetUsersByRole(context.Context, *GetUsersByRoleRequest) (*GetUsersByRoleResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUsersByRole not implemented")
}
func (UnimplementedAuthAdminServiceServer) CreateUser(context.Context, *CreateUserRequest) (*CreateUserResponse, error) {
return nil, status.Error(codes.Unimplemented, "method CreateUser not implemented")
}
func (UnimplementedAuthAdminServiceServer) GetUserSessions(context.Context, *GetUserSessionsRequest) (*GetUserSessionsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method GetUserSessions not implemented")
}
func (UnimplementedAuthAdminServiceServer) ClearUserSessions(context.Context, *ClearUserSessionsRequest) (*ClearUserSessionsResponse, error) {
return nil, status.Error(codes.Unimplemented, "method ClearUserSessions not implemented")
}
func (UnimplementedAuthAdminServiceServer) mustEmbedUnimplementedAuthAdminServiceServer() {}
func (UnimplementedAuthAdminServiceServer) testEmbeddedByValue() {}
// UnsafeAuthAdminServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to AuthAdminServiceServer will
// result in compilation errors.
type UnsafeAuthAdminServiceServer interface {
mustEmbedUnimplementedAuthAdminServiceServer()
}
func RegisterAuthAdminServiceServer(s grpc.ServiceRegistrar, srv AuthAdminServiceServer) {
// If the following call panics, it indicates UnimplementedAuthAdminServiceServer was
// embedded by pointer and is nil. This will cause panics if an
// unimplemented method is ever invoked, so we test this at initialization
// time to prevent it from happening at runtime later due to I/O.
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
t.testEmbeddedByValue()
}
s.RegisterService(&AuthAdminService_ServiceDesc, srv)
}
func _AuthAdminService_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUserRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetUser(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetUser_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetUser(ctx, req.(*GetUserRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUsersRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetUsers(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetUsers_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetUsers(ctx, req.(*GetUsersRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetUsersByUsernames_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUsersByUsernamesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetUsersByUsernames(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetUsersByUsernames_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetUsersByUsernames(ctx, req.(*GetUsersByUsernamesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_DeleteUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DeleteUserRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).DeleteUser(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_DeleteUser_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).DeleteUser(ctx, req.(*DeleteUserRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_RestoreUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RestoreUserRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).RestoreUser(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_RestoreUser_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).RestoreUser(ctx, req.(*RestoreUserRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_AssignRoleToUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(AssignRoleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).AssignRoleToUser(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_AssignRoleToUser_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).AssignRoleToUser(ctx, req.(*AssignRoleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_UnassignRoleFromUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UnassignRoleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).UnassignRoleFromUser(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_UnassignRoleFromUser_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).UnassignRoleFromUser(ctx, req.(*UnassignRoleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetRoleDetails_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetRoleDetailsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetRoleDetails(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetRoleDetails_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetRoleDetails(ctx, req.(*GetRoleDetailsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetRoleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetRole(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetRole_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetRole(ctx, req.(*GetRoleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetUserRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUserRoleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetUserRole(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetUserRole_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetUserRole(ctx, req.(*GetUserRoleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_SearchUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SearchUsersRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).SearchUsers(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_SearchUsers_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).SearchUsers(ctx, req.(*SearchUsersRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_CountUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CountUsersRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).CountUsers(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_CountUsers_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).CountUsers(ctx, req.(*CountUsersRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_SearchRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SearchRolesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).SearchRoles(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_SearchRoles_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).SearchRoles(ctx, req.(*SearchRolesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetRoleScopes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetRoleScopesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetRoleScopes(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetRoleScopes_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetRoleScopes(ctx, req.(*GetRoleScopesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetUserWithRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUserWithRolesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetUserWithRoles(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetUserWithRoles_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetUserWithRoles(ctx, req.(*GetUserWithRolesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetAssignableRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetAssignableRolesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetAssignableRoles(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetAssignableRoles_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetAssignableRoles(ctx, req.(*GetAssignableRolesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_UpdateUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(UpdateUserInfoRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).UpdateUserInfo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_UpdateUserInfo_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).UpdateUserInfo(ctx, req.(*UpdateUserInfoRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetScopeAncestors_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetScopeAncestorsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetScopeAncestors(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetScopeAncestors_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetScopeAncestors(ctx, req.(*GetScopeAncestorsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetScopeDescendants_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetScopeDescendantsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetScopeDescendants(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetScopeDescendants_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetScopeDescendants(ctx, req.(*GetScopeDescendantsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetAssignableTargets_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetAssignableTargetsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetAssignableTargets(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetAssignableTargets_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetAssignableTargets(ctx, req.(*GetAssignableTargetsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetUsersByRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUsersByRoleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetUsersByRole(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetUsersByRole_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetUsersByRole(ctx, req.(*GetUsersByRoleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_CreateUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CreateUserRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).CreateUser(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_CreateUser_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).CreateUser(ctx, req.(*CreateUserRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_GetUserSessions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetUserSessionsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).GetUserSessions(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_GetUserSessions_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).GetUserSessions(ctx, req.(*GetUserSessionsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _AuthAdminService_ClearUserSessions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ClearUserSessionsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(AuthAdminServiceServer).ClearUserSessions(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: AuthAdminService_ClearUserSessions_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(AuthAdminServiceServer).ClearUserSessions(ctx, req.(*ClearUserSessionsRequest))
}
return interceptor(ctx, in, info, handler)
}
// AuthAdminService_ServiceDesc is the grpc.ServiceDesc for AuthAdminService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var AuthAdminService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "st_peter.admin.AuthAdminService",
HandlerType: (*AuthAdminServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetUser",
Handler: _AuthAdminService_GetUser_Handler,
},
{
MethodName: "GetUsers",
Handler: _AuthAdminService_GetUsers_Handler,
},
{
MethodName: "GetUsersByUsernames",
Handler: _AuthAdminService_GetUsersByUsernames_Handler,
},
{
MethodName: "DeleteUser",
Handler: _AuthAdminService_DeleteUser_Handler,
},
{
MethodName: "RestoreUser",
Handler: _AuthAdminService_RestoreUser_Handler,
},
{
MethodName: "AssignRoleToUser",
Handler: _AuthAdminService_AssignRoleToUser_Handler,
},
{
MethodName: "UnassignRoleFromUser",
Handler: _AuthAdminService_UnassignRoleFromUser_Handler,
},
{
MethodName: "GetRoleDetails",
Handler: _AuthAdminService_GetRoleDetails_Handler,
},
{
MethodName: "GetRole",
Handler: _AuthAdminService_GetRole_Handler,
},
{
MethodName: "GetUserRole",
Handler: _AuthAdminService_GetUserRole_Handler,
},
{
MethodName: "SearchUsers",
Handler: _AuthAdminService_SearchUsers_Handler,
},
{
MethodName: "CountUsers",
Handler: _AuthAdminService_CountUsers_Handler,
},
{
MethodName: "SearchRoles",
Handler: _AuthAdminService_SearchRoles_Handler,
},
{
MethodName: "GetRoleScopes",
Handler: _AuthAdminService_GetRoleScopes_Handler,
},
{
MethodName: "GetUserWithRoles",
Handler: _AuthAdminService_GetUserWithRoles_Handler,
},
{
MethodName: "GetAssignableRoles",
Handler: _AuthAdminService_GetAssignableRoles_Handler,
},
{
MethodName: "UpdateUserInfo",
Handler: _AuthAdminService_UpdateUserInfo_Handler,
},
{
MethodName: "GetScopeAncestors",
Handler: _AuthAdminService_GetScopeAncestors_Handler,
},
{
MethodName: "GetScopeDescendants",
Handler: _AuthAdminService_GetScopeDescendants_Handler,
},
{
MethodName: "GetAssignableTargets",
Handler: _AuthAdminService_GetAssignableTargets_Handler,
},
{
MethodName: "GetUsersByRole",
Handler: _AuthAdminService_GetUsersByRole_Handler,
},
{
MethodName: "CreateUser",
Handler: _AuthAdminService_CreateUser_Handler,
},
{
MethodName: "GetUserSessions",
Handler: _AuthAdminService_GetUserSessions_Handler,
},
{
MethodName: "ClearUserSessions",
Handler: _AuthAdminService_ClearUserSessions_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "st-peter-admin.proto",
}

556
proto/st-peter-admin.proto Normal file
View File

@ -0,0 +1,556 @@
syntax = "proto3";
package st_peter.admin;
option go_package = "nandie.com/pkg/;auth_admin_service";
import "google/protobuf/timestamp.proto";
message Date {
int32 year = 1;
uint32 month = 2;
uint32 day = 3;
}
service AuthAdminService {
rpc GetUser (GetUserRequest) returns (UserResponse);
rpc GetUsers (GetUsersRequest) returns (UsersResponse);
// System-token-authed minimal lookup: id + display name ONLY (no PII).
// Auth is the shared system token alone (no actor) internal services only,
// so viewing content (e.g. history) can't be used to harvest user info.
rpc GetUsersData (GetUsersDataRequest) returns (GetUsersDataResponse);
rpc GetUsersByUsernames(GetUsersByUsernamesRequest) returns (UsersResponse);
rpc DeleteUser (DeleteUserRequest) returns (OperationResponse);
rpc RestoreUser (RestoreUserRequest) returns (OperationResponse);
rpc AssignRoleToUser (AssignRoleRequest) returns (GetUserWithRolesResponse);
rpc UnassignRoleFromUser (UnassignRoleRequest) returns (GetUserWithRolesResponse);
rpc GetRoleDetails (GetRoleDetailsRequest) returns (GetRoleDetailsResponse);
rpc GetRole(GetRoleRequest) returns (GetRoleResponse);
rpc GetUserRole(GetUserRoleRequest) returns (GetUserRoleResponse);
rpc SearchUsers (SearchUsersRequest) returns (SearchUsersResponse);
rpc CountUsers (CountUsersRequest) returns (CountUsersResponse);
rpc SearchRoles (SearchRolesRequest) returns (SearchRolesResponse);
rpc GetRoleScopes (GetRoleScopesRequest) returns (GetRoleScopesResponse);
rpc GetUserWithRoles (GetUserWithRolesRequest) returns (GetUserWithRolesResponse);
rpc GetAssignableRoles (GetAssignableRolesRequest) returns (GetAssignableRolesResponse);
rpc UpdateUserInfo (UpdateUserInfoRequest) returns (UpdateUserInfoResponse);
rpc GetScopeAncestors (GetScopeAncestorsRequest) returns (GetScopeAncestorsResponse);
rpc GetScopeDescendants (GetScopeDescendantsRequest) returns (GetScopeDescendantsResponse);
rpc GetAssignableTargets (GetAssignableTargetsRequest) returns (GetAssignableTargetsResponse);
rpc GetUsersByRole (GetUsersByRoleRequest) returns (GetUsersByRoleResponse);
rpc CreateUser (CreateUserRequest) returns (CreateUserResponse);
rpc GetUserSessions (GetUserSessionsRequest) returns (GetUserSessionsResponse);
rpc ClearUserSessions (ClearUserSessionsRequest) returns (ClearUserSessionsResponse);
}
enum ResultCode {
RESULT_CODE_SUCCESS = 0;
RESULT_CODE_BAD_INPUT = 1;
RESULT_CODE_NOT_FOUND = 2;
RESULT_CODE_INTERNAL_SERVER_ERROR = 3;
RESULT_CODE_NOT_AUTHORIZED = 4; // User is not authenticated
RESULT_CODE_FORBIDDEN = 5; // User is authenticated but lacks required permissions
}
message User {
string id = 1;
string email = 2;
string phone = 3;
string first_names = 4;
string last_name = 5;
string profile_picture_url = 6;
optional string handle = 7;
google.protobuf.Timestamp created_at = 10;
google.protobuf.Timestamp updated_at = 11;
google.protobuf.Timestamp deleted_at = 12;
optional google.protobuf.Timestamp last_login = 13;
bool is_active = 20;
bool is_email_verified = 21;
bool is_phone_verified = 22;
Date date_of_birth = 23;
int64 version = 24;
repeated SocialAccount social_accounts = 30;
}
message Role {
string id = 1;
string code = 2;
string description = 3;
google.protobuf.Timestamp created_at = 4;
google.protobuf.Timestamp updated_at = 5;
}
message SocialAccount {
string provider = 1;
string provider_user_id = 2;
string access_token = 3;
google.protobuf.Timestamp expires_at = 4;
}
message RegisterUserRequest {
string email = 1;
string password = 2;
string phone = 3;
string first_name = 4;
string last_name = 5;
}
message UserResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
User user = 4;
}
message LoginRequest {
string email = 1;
string password = 2;
}
message AuthenticationResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
string token = 4;
User user = 5;
}
message GetUserRequest {
string user_id = 1;
string actor_id = 11;
string actor_token = 12;
}
message GetUsersByUsernamesRequest {
repeated string email_addresses = 2;
repeated string phone_numbers = 3;
string actor_id = 11;
string actor_token = 12;
}
message DeleteUserRequest {
string actor_id = 1;
string actor_token = 2;
string user_id = 3;
string reason = 4;
string user_agent = 5;
bool unassign_roles = 6;
}
message RestoreUserRequest {
string actor_id = 1;
string actor_token = 2;
string user_id = 3;
string reason = 4;
string user_agent = 5;
bool restore_roles = 6;
}
message AssignRoleRequest {
string actor_id = 1;
string actor_token = 2;
string user_id = 5;
string role_id = 6;
string scope_code = 7;
optional string target_id = 8;
google.protobuf.Timestamp expires_at = 9;
string session_id = 10;
}
message UnassignRoleRequest {
string actor_id = 1;
string actor_token = 2;
string user_id = 5;
string user_role_id = 6;
string reason = 7;
}
message OperationResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
}
message SearchUsersRequest {
string actor_id = 1;
string actor_token = 2;
optional string email = 3;
optional string phone = 4;
optional string search = 11;
int32 page = 12;
int32 page_size = 13;
bool include_inactive = 14;
}
message CountUsersRequest {
string actor_id = 1;
string actor_token = 2;
}
message TimeSeriesStatistic {
uint32 count = 1;
int64 year = 3;
uint32 month = 4;
uint32 day = 5;
uint32 hour = 6;
}
message CountUsersResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
uint32 grand_total = 4;
Date current_date = 7;
repeated TimeSeriesStatistic daily = 5; // 30 past days
repeated TimeSeriesStatistic monthly = 6; // 12 months
}
message SearchUsersResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated User users = 4;
int32 total = 5;
}
message SearchRolesRequest {
string actor_id = 1;
string actor_token = 2;
string search = 11;
int32 page = 12;
int32 page_size = 13;
}
message SearchRolesResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated Role roles = 4;
int32 total = 5;
}
message GetRoleScopesRequest {
string actor_id = 1;
string actor_token = 2;
optional string role_id = 3;
optional string scope_code = 4;
}
message GetRoleScopesResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated RoleScope role_scopes = 4;
map<string, Role> roles = 5;
}
message Lookup {
string code = 1;
string name = 2;
string description = 3;
}
message Scope {
string code = 1;
string description = 2;
optional string parent_code = 3;
bool is_active = 4;
}
message GetUserWithRolesRequest {
string actor_id = 1;
string actor_token = 2;
string user_id = 3;
bool include_inactive = 4;
repeated string scope_codes = 5;
repeated string role_names = 6;
}
message GetUserWithRolesResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
User user = 4;
map<string, Role> roles = 5;
repeated UserRole assigned_roles = 6;
map<string, Scope> scopes = 7;
map<string, User> actors = 8;
}
message UserRole {
string id =1;
string user_id = 2;
string role_id = 3;
string scope_code = 4;
optional string target_id = 5;
bool is_active = 6;
google.protobuf.Timestamp created_at = 11;
string created_by = 12;
google.protobuf.Timestamp updated_at = 13;
string updated_by = 14;
google.protobuf.Timestamp expires_at = 15;
google.protobuf.Timestamp deleted_at = 16;
optional string deleted_by = 17;
}
message GetUsersRequest {
string actor_id = 1;
string actor_token = 2;
repeated string user_ids = 3;
}
message UsersResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated User users = 4;
}
// GetUsersData system-token-only, returns the MINIMUM for display: id + a
// resolved display name. Deliberately omits email/phone/PII so even a trusted
// internal caller can't harvest contact info through it.
message GetUsersDataRequest {
string system_token = 1;
repeated string user_ids = 2;
}
message UserData {
string id = 1;
string name = 2;
}
message GetUsersDataResponse {
bool success = 1;
repeated UserData users = 2;
}
message GetAssignableRolesRequest {
string actor_id = 1;
string actor_token = 2;
string user_id = 3;
}
message ScopeList {
repeated string scope_codes = 1;
}
message GetAssignableRolesResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated RoleScopeTarget roles = 4;
repeated Scope scopes = 5;
map<string, ScopeList> role_scopes = 6;
}
message RoleScopeTarget {
Role role = 1;
Scope scope = 2;
string target_id = 3;
google.protobuf.Timestamp expires_at = 7;
}
message GetRoleDetailsRequest{
string actor_id = 1;
string actor_token = 2;
string role_id = 3;
}
message RoleScope {
string id = 1;
string role_id = 2;
string scope_code = 3;
bool is_active = 4;
}
message GetRoleDetailsResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
Role role = 4;
repeated UserRole assigned_roles = 5;
repeated Scope scopes = 6;
repeated User actors = 7;
repeated RoleScope role_scopes = 8;
}
message GetRoleRequest {
string actor_id = 1;
string actor_token = 2;
string role_id = 3;
}
message GetRoleResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
Role role = 4;
}
message GetUserRoleRequest {
string actor_id = 1;
string actor_token = 2;
string user_role_id = 3;
}
message GetUserRoleResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
UserRole user_role = 4;
Role role = 5;
Scope scope = 6;
}
message UpdateUserInfoRequest {
string actor_id = 1;
string actor_token = 2;
string user_id = 3;
optional string first_names = 4;
optional string last_name = 5;
optional string profile_picture_id = 6;
Date date_of_birth = 7;
optional string handle = 8; // Optional unique handle (e.g., @username)
}
message UpdateUserInfoResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
User user = 4;
}
message GetScopeAncestorsRequest {
string actor_id = 1;
string actor_token = 2;
string scope_code = 3;
}
message GetScopeAncestorsResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated Scope ancestors = 4;
}
message GetScopeDescendantsRequest {
string actor_id = 1;
string actor_token = 2;
string scope_code = 3;
}
message GetScopeDescendantsResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated Scope descendants = 4;
}
message GetAssignableTargetsRequest {
string actor_id = 1;
string actor_token = 2;
string scope_code = 3;
}
message GetAssignableTargetsResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated string target_ids = 4;
bool all_targets_permissible = 5;
}
message GetUsersByRoleRequest {
string actor_id = 1;
string actor_token = 2;
string role_id = 3;
optional string scope_code = 4;
optional string target_id = 5;
bool include_inactive = 6;
}
message GetUsersByRoleResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated User users = 4;
int32 total = 5;
}
message CreateUserRequest {
string actor_id = 1;
string actor_token = 2;
optional string email = 3;
optional string phone = 4;
string first_names = 5;
string last_name = 6;
string profile_picture_url = 7;
optional string password = 8; // Optional, if not provided, a random password will be generated and returned.
optional Date date_of_birth = 9;
optional string handle = 10; // Optional unique handle (e.g., @username)
}
message CreateUserResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
User user = 4;
optional string password = 5; // Only returned if a new password was generated
}
message DeviceInfo {
string application_name = 1;
string application_version = 2;
string device_name = 3;
string device_type = 4;
string device_os = 5;
string device_os_version = 6;
string device_id = 7;
}
message UserSession {
string id = 1;
string user_id = 2;
DeviceInfo device_info = 3;
google.protobuf.Timestamp created_at = 4;
google.protobuf.Timestamp expires_at = 5;
google.protobuf.Timestamp last_activity = 6;
bool is_active = 7;
string ip_address = 8;
string user_agent = 9;
}
message GetUserSessionsRequest {
string actor_id = 1;
string actor_token = 2;
string user_id = 3; // The user whose sessions to retrieve
int32 page = 4;
int32 size = 5;
}
message GetUserSessionsResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
repeated UserSession sessions = 4;
int32 total = 5;
}
message ClearUserSessionsRequest {
string actor_id = 1;
string actor_token = 2;
string user_id = 3; // The user whose sessions should be cleared
repeated string session_ids = 4; // If empty, clears all sessions for the user
}
message ClearUserSessionsResponse {
bool success = 1;
ResultCode result_code = 2;
string message = 3;
int32 cleared_count = 4;
}

View File

@ -1,6 +1,6 @@
[package]
name = "st-peter-client"
version = "0.2.0"
version = "0.2.3"
edition = "2021"
description = "Official Rust client for st-peter (aura-users) — authentication over gRPC with a token-verify cache"
repository = "https://git.awesomike.com/pub/st-peter-client"

View File

@ -1,7 +1,10 @@
// Compile the vendored proto (../proto, synced from the st-peter server repo)
// into client stubs. Client-only: no server traits are generated.
fn main() {
let protos = ["../proto/st-peter-auth.proto"];
let protos = [
"../proto/st-peter-auth.proto",
"../proto/st-peter-admin.proto",
];
tonic_prost_build::configure()
.build_server(false)
.compile_protos(&protos, &["../proto"])

View File

@ -43,6 +43,14 @@ pub mod authpb {
tonic::include_proto!("st_peter.auth");
}
/// Admin proto stubs (`AuthAdminService` — user + targeted-role administration).
/// Generated from `proto/st-peter-admin.proto` (package `st_peter.admin`).
/// All RPCs are **actor-credentialed**: aura-users authorizes the acting admin
/// by its own assignability rules, not the channel.
pub mod adminpb {
tonic::include_proto!("st_peter.admin");
}
use authpb::auth_service_client::AuthServiceClient;
use authpb::{
AuthenticatedUser, AuthenticationResponse, LoginRequest, LookupUserRequest, User,
@ -56,6 +64,10 @@ pub enum Error {
/// The token failed verification (or the response carried no user).
#[error("unauthorized")]
Unauthorized,
/// aura-users processed the call but rejected it (`success = false`) —
/// carries the result code and display message.
#[error("rejected by aura-users ({code:?}): {message}")]
Rejected { code: i32, message: String },
/// RPC-level failure talking to aura-users.
#[error(transparent)]
Rpc(#[from] tonic::Status),
@ -137,10 +149,22 @@ impl AuthClient {
})
}
/// Verify a session token, returning the authenticated user (+ platform
/// roles). Cached ~60s to avoid a gRPC round-trip per request.
/// Verify a session token, returning the authenticated user with **all**
/// of their roles. Cached ~60s to avoid a gRPC round-trip per request.
pub async fn verify_token(&self, token: &str) -> Result<AuthenticatedUser> {
let key = token_hash(token);
self.verify_token_scoped(token, &[]).await
}
/// Verify a session token, returning roles **filtered to the given
/// scopes** (e.g. `["cms"]`) — each service pulls only its own scope's
/// roles. Empty `role_scopes` = all roles. Cached ~60s per
/// `(token, scopes)` combination.
pub async fn verify_token_scoped(
&self,
token: &str,
role_scopes: &[&str],
) -> Result<AuthenticatedUser> {
let key = cache_key(token, role_scopes);
let ttl = std::time::Duration::from_secs(AUTH_CACHE_TTL_SECS);
// Read under the lock, clone out, and drop the guard before any `.await`.
@ -157,8 +181,8 @@ impl AuthClient {
let resp = client
.verify_token(VerifyTokenRequest {
token: token.to_string(),
include_user_roles: true, // platform roles; service roles stay local
role_scopes: vec![],
include_user_roles: true,
role_scopes: role_scopes.iter().map(|s| s.to_string()).collect(),
role_names: vec![],
})
.await?
@ -210,6 +234,99 @@ impl AuthClient {
Ok(interpret_auth_response(resp))
}
/// Verify a service **API key** (`VerifyApiKey` — same response shape as
/// token verification): yields the key's **owning service user** plus that
/// user's roles, so consumers build their `Ctx` identically to a session
/// (the producer seam: a service user holds targeted roles like anyone).
/// Cached ~60s per key, like tokens.
pub async fn verify_api_key(&self, api_key: &str) -> Result<AuthenticatedUser> {
let key = cache_key(api_key, &["#api-key"]); // namespaced away from tokens
let ttl = std::time::Duration::from_secs(AUTH_CACHE_TTL_SECS);
if let Some(u) = {
let cache = self.cache.read().await;
cache
.get(&key)
.and_then(|(u, at)| (at.elapsed() < ttl).then(|| u.clone()))
} {
return Ok(u);
}
let mut client = self.inner.clone();
let resp = client
.verify_api_key(authpb::VerifyApiKeyRequest {
api_key: api_key.to_string(),
})
.await?
.into_inner();
if !resp.success {
return Err(Error::Unauthorized);
}
let user = resp.authenticated_user.ok_or(Error::Unauthorized)?;
self.cache
.write()
.await
.insert(key, (user.clone(), std::time::Instant::now()));
Ok(user)
}
/// Mint an API key for the session's user (`full key returned ONCE`).
pub async fn create_api_key(
&self,
token: &str,
name: &str,
scopes: Vec<String>,
expires_at: i64, // 0 = never
) -> Result<authpb::CreateApiKeyResponse> {
let resp = self
.inner
.clone()
.create_api_key(authpb::CreateApiKeyRequest {
token: token.to_string(),
name: name.to_string(),
scopes,
expires_at,
})
.await?
.into_inner();
if !resp.success {
return Err(Error::Rejected { code: resp.result_code, message: resp.message });
}
Ok(resp)
}
/// List the session user's API keys.
pub async fn list_api_keys(&self, token: &str) -> Result<Vec<authpb::ApiKeyInfo>> {
let resp = self
.inner
.clone()
.list_api_keys(authpb::ListApiKeysRequest { token: token.to_string() })
.await?
.into_inner();
if !resp.success {
return Err(Error::Rejected { code: resp.result_code, message: resp.message });
}
Ok(resp.keys)
}
/// Revoke an API key by id.
pub async fn revoke_api_key(&self, token: &str, key_id: &str) -> Result<()> {
let resp = self
.inner
.clone()
.revoke_api_key(authpb::RevokeApiKeyRequest {
token: token.to_string(),
key_id: key_id.to_string(),
})
.await?
.into_inner();
if !resp.success {
return Err(Error::Rejected { code: resp.result_code, message: resp.message });
}
Ok(())
}
/// Resolve a st-peter user by exact identifier (email / phone / handle).
///
/// Typical use: a service-admin role-grant page — resolve a colleague's
@ -240,6 +357,350 @@ impl AuthClient {
}
}
/// The acting administrator's identity. Admin RPCs are **actor-credentialed**:
/// every request carries the actor's own user id + session token, and
/// aura-users authorizes the *actor* by its assignability rules (global
/// administrator / scoped administrator / `{prefix}-admin` restricted to its
/// own target) — a client cannot grant beyond what the actor may grant.
#[derive(Clone)]
pub struct Actor {
pub user_id: String,
pub token: String,
}
/// Thin client to aura-users' `AuthAdminService` — user administration and
/// **targeted-role** management. Methods gate on `success` (mapping failures
/// to [`Error::Rejected`]) and otherwise return the generated response types
/// from [`adminpb`]; use [`AdminClient::raw`] for RPCs without a wrapper.
#[derive(Clone)]
pub struct AdminClient {
inner: adminpb::auth_admin_service_client::AuthAdminServiceClient<Channel>,
}
/// Gate an admin response on its `success` flag.
macro_rules! admin_ok {
($resp:expr) => {{
let resp = $resp;
if !resp.success {
return Err(Error::Rejected { code: resp.result_code, message: resp.message });
}
Ok(resp)
}};
}
impl AdminClient {
/// Connect to aura-users gRPC (same endpoint as [`AuthClient`]; lazy dial).
pub async fn connect(grpc_url: &str) -> Result<Self> {
let channel = Channel::from_shared(grpc_url.to_string())?
.connect_timeout(std::time::Duration::from_secs(5))
.timeout(std::time::Duration::from_secs(10))
.connect_lazy();
Ok(Self {
inner: adminpb::auth_admin_service_client::AuthAdminServiceClient::new(channel),
})
}
/// The raw generated client, for the RPCs without an ergonomic wrapper.
pub fn raw(&self) -> adminpb::auth_admin_service_client::AuthAdminServiceClient<Channel> {
self.inner.clone()
}
/// System-token user lookup — returns ONLY id + display name (no PII).
/// Authorizes on the shared `system_token` alone (no actor), so an internal
/// service can label "who did this" (e.g. content history) without the
/// end-user's credentials and without exposing contact info. The token must
/// be one registered in st-peter's `system-tokens`.
pub async fn get_users_data(
&self,
system_token: &str,
user_ids: Vec<String>,
) -> Result<Vec<adminpb::UserData>> {
let resp = self
.inner
.clone()
.get_users_data(adminpb::GetUsersDataRequest {
system_token: system_token.to_string(),
user_ids,
})
.await?
.into_inner();
Ok(resp.users)
}
/// Assign a role to a user — targeted when `target_id` is set (the
/// multi-tenancy device: e.g. `cms-content-editor` for one organization),
/// optionally time-bound via `expires_at`.
pub async fn assign_role(
&self,
actor: &Actor,
user_id: &str,
role_id: &str,
scope_code: &str,
target_id: Option<String>,
expires_at: Option<prost_types::Timestamp>,
) -> Result<adminpb::GetUserWithRolesResponse> {
let resp = self
.inner
.clone()
.assign_role_to_user(adminpb::AssignRoleRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
user_id: user_id.to_string(),
role_id: role_id.to_string(),
scope_code: scope_code.to_string(),
target_id,
expires_at,
session_id: String::new(),
})
.await?
.into_inner();
admin_ok!(resp)
}
/// Revoke an assignment by its `user_role_id` (soft-delete, audited in
/// aura-users).
pub async fn unassign_role(
&self,
actor: &Actor,
user_id: &str,
user_role_id: &str,
reason: &str,
) -> Result<adminpb::GetUserWithRolesResponse> {
let resp = self
.inner
.clone()
.unassign_role_from_user(adminpb::UnassignRoleRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
user_id: user_id.to_string(),
user_role_id: user_role_id.to_string(),
reason: reason.to_string(),
})
.await?
.into_inner();
admin_ok!(resp)
}
/// What may this actor grant, and where — drives role-picker UIs.
pub async fn get_assignable_roles(
&self,
actor: &Actor,
user_id: &str,
) -> Result<adminpb::GetAssignableRolesResponse> {
let resp = self
.inner
.clone()
.get_assignable_roles(adminpb::GetAssignableRolesRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
user_id: user_id.to_string(),
})
.await?
.into_inner();
admin_ok!(resp)
}
/// Which targets may this actor grant for, within a scope
/// (`all_targets_permissible` = untargeted admin).
pub async fn get_assignable_targets(
&self,
actor: &Actor,
scope_code: &str,
) -> Result<adminpb::GetAssignableTargetsResponse> {
let resp = self
.inner
.clone()
.get_assignable_targets(adminpb::GetAssignableTargetsRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
scope_code: scope_code.to_string(),
})
.await?
.into_inner();
admin_ok!(resp)
}
/// A user plus their assignments, optionally filtered by scope.
pub async fn get_user_with_roles(
&self,
actor: &Actor,
user_id: &str,
scope_codes: Vec<String>,
) -> Result<adminpb::GetUserWithRolesResponse> {
let resp = self
.inner
.clone()
.get_user_with_roles(adminpb::GetUserWithRolesRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
user_id: user_id.to_string(),
include_inactive: false,
scope_codes,
role_names: vec![],
})
.await?
.into_inner();
admin_ok!(resp)
}
/// Paged platform-user search (email / phone / free text).
pub async fn search_users(
&self,
actor: &Actor,
search: Option<String>,
page: i32,
page_size: i32,
) -> Result<adminpb::SearchUsersResponse> {
let resp = self
.inner
.clone()
.search_users(adminpb::SearchUsersRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
email: None,
phone: None,
search,
page,
page_size,
include_inactive: false,
})
.await?
.into_inner();
admin_ok!(resp)
}
/// Who holds a role — optionally narrowed to a scope and/or target
/// ("list this org's editors").
pub async fn get_users_by_role(
&self,
actor: &Actor,
role_id: &str,
scope_code: Option<String>,
target_id: Option<String>,
) -> Result<adminpb::GetUsersByRoleResponse> {
let resp = self
.inner
.clone()
.get_users_by_role(adminpb::GetUsersByRoleRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
role_id: role_id.to_string(),
scope_code,
target_id,
include_inactive: false,
})
.await?
.into_inner();
admin_ok!(resp)
}
/// Onboard a user (invite flow). Caller builds the request (many optional
/// identity fields); actor credentials are filled in here.
pub async fn create_user(
&self,
actor: &Actor,
mut req: adminpb::CreateUserRequest,
) -> Result<adminpb::CreateUserResponse> {
req.actor_id = actor.user_id.clone();
req.actor_token = actor.token.clone();
let resp = self.inner.clone().create_user(req).await?.into_inner();
admin_ok!(resp)
}
/// Soft-delete a user (optionally unassigning their roles).
pub async fn delete_user(
&self,
actor: &Actor,
user_id: &str,
reason: &str,
unassign_roles: bool,
) -> Result<adminpb::OperationResponse> {
let resp = self
.inner
.clone()
.delete_user(adminpb::DeleteUserRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
user_id: user_id.to_string(),
reason: reason.to_string(),
user_agent: String::new(),
unassign_roles,
})
.await?
.into_inner();
admin_ok!(resp)
}
/// Restore a soft-deleted user (optionally restoring their roles).
pub async fn restore_user(
&self,
actor: &Actor,
user_id: &str,
reason: &str,
restore_roles: bool,
) -> Result<adminpb::OperationResponse> {
let resp = self
.inner
.clone()
.restore_user(adminpb::RestoreUserRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
user_id: user_id.to_string(),
reason: reason.to_string(),
user_agent: String::new(),
restore_roles,
})
.await?
.into_inner();
admin_ok!(resp)
}
/// A user's active sessions (support view).
pub async fn get_user_sessions(
&self,
actor: &Actor,
user_id: &str,
page: i32,
size: i32,
) -> Result<adminpb::GetUserSessionsResponse> {
let resp = self
.inner
.clone()
.get_user_sessions(adminpb::GetUserSessionsRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
user_id: user_id.to_string(),
page,
size,
})
.await?
.into_inner();
admin_ok!(resp)
}
/// Force logout: clear the given sessions, or ALL of the user's sessions
/// when `session_ids` is empty.
pub async fn clear_user_sessions(
&self,
actor: &Actor,
user_id: &str,
session_ids: Vec<String>,
) -> Result<adminpb::ClearUserSessionsResponse> {
let resp = self
.inner
.clone()
.clear_user_sessions(adminpb::ClearUserSessionsRequest {
actor_id: actor.user_id.clone(),
actor_token: actor.token.clone(),
user_id: user_id.to_string(),
session_ids,
})
.await?
.into_inner();
admin_ok!(resp)
}
}
/// Extract a `Bearer <token>` from an `Authorization` header map. The shared
/// convention across aura services is: Bearer header first, then the
/// [`COOKIE_NAME`] session cookie.
@ -252,10 +713,13 @@ pub fn bearer(headers: &http::HeaderMap) -> Option<String> {
.map(|s| s.trim().to_string())
}
/// Fast (non-cryptographic) hash of the token, used only as the cache key.
fn token_hash(token: &str) -> u64 {
/// Fast (non-cryptographic) hash of (token, scope filter), used only as the
/// cache key — the same token verified under different scope filters returns
/// different role sets and must not share an entry.
fn cache_key(token: &str, role_scopes: &[&str]) -> u64 {
use std::hash::{Hash, Hasher};
let mut h = std::collections::hash_map::DefaultHasher::new();
token.hash(&mut h);
role_scopes.hash(&mut h);
h.finish()
}

View File

@ -12,6 +12,7 @@ MOD=git.awesomike.com/pub/st-peter-client/go
# proto filename (relative to ../proto) -> Go package dir under the module
protos=(
st-peter-auth.proto:genpb/auth
st-peter-admin.proto:genpb/admin
)
files=()

View File

@ -19,6 +19,7 @@ protoc -I ../proto \
--plugin=protoc-gen-ts_proto="$plugin" \
--ts_proto_out="$out" \
--ts_proto_opt=outputServices=grpc-js,esModuleInterop=true,env=node,useExactTypes=false,unrecognizedEnum=false \
st-peter-auth.proto
st-peter-auth.proto \
st-peter-admin.proto
echo "Generated TypeScript stubs under ts/src/genpb/"

View File

@ -25,11 +25,13 @@ if [[ ! -f "$ST_PETER_REPO/Cargo.toml" ]]; then
fi
# canonical path in st-peter-lib -> filename in proto/
# NOTE: st-peter-admin.proto (the admin surface) and health.proto are
# intentionally NOT vendored — services authenticate users; they do not
# administer st-peter.
# NOTE: health.proto is intentionally NOT vendored (deployment concern, not a
# client surface). The admin proto IS vendored: services with delegated
# administration (targeted-role grants, user admin) drive AuthAdminService
# with the acting admin's own credentials.
protos=(
"proto/st-peter-auth.proto"
"proto/st-peter-admin.proto"
)
dest="$here/proto"

View File

@ -1,6 +1,6 @@
{
"name": "@st-peter/client",
"version": "0.2.0",
"version": "0.2.2",
"description": "Official TypeScript client for st-peter (aura-users) — authentication over gRPC with a token-verify cache",
"repository": "https://git.awesomike.com/pub/st-peter-client",
"license": "MIT OR Apache-2.0",

Binary file not shown.

10218
ts/src/genpb/st-peter-admin.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -6,5 +6,8 @@ export {
} from "./auth";
export type { LoginOutcome, ConnectOptions } from "./auth";
// Raw wire surface for callers that need it.
// Raw wire surface for callers that need it. The admin surface
// (AuthAdminServiceClient — user + targeted-role administration) is exposed
// as generated stubs; ergonomic wrappers exist in the Rust client first.
export * as authpb from "./genpb/st-peter-auth";
export * as adminpb from "./genpb/st-peter-admin";