diff --git a/config/crd/bases/iam/iam.miloapis.com_users.yaml b/config/crd/bases/iam/iam.miloapis.com_users.yaml
index e548140f..f7794447 100644
--- a/config/crd/bases/iam/iam.miloapis.com_users.yaml
+++ b/config/crd/bases/iam/iam.miloapis.com_users.yaml
@@ -146,6 +146,16 @@ spec:
- type
type: object
type: array
+ lastLoginPerProvider:
+ additionalProperties:
+ type: string
+ description: |-
+ LastLoginPerProvider tracks the most recent login timestamp for each identity provider
+ that the user has used to authenticate. The map key is the provider name (e.g., "github", "google")
+ and the value is the RFC3339 timestamp of the last successful login via that provider.
+ This field is updated by the auth provider when processing idpintent.succeeded events.
+ Note: This event is only triggered during actual IDP login, not on token refresh.
+ type: object
lastLoginProvider:
allOf:
- enum:
@@ -159,6 +169,14 @@ spec:
user to log in (e.g., "github" or "google"). This field is set by the auth provider
based on authentication events.
type: string
+ lastTokenIntrospection:
+ description: |-
+ LastTokenIntrospection records the timestamp of the most recent successful token introspection
+ for this user. This is updated during authentication webhook calls when validating access tokens,
+ which occurs more frequently than actual IDP logins (including token refreshes).
+ The value is an RFC3339 timestamp.
+ format: date-time
+ type: string
registrationApproval:
description: |-
RegistrationApproval represents the administrator’s decision on the user’s registration request.
diff --git a/docs/api/iam.md b/docs/api/iam.md
index 1ee17986..2f3a312f 100644
--- a/docs/api/iam.md
+++ b/docs/api/iam.md
@@ -3827,6 +3827,17 @@ populated by the auth provider or any service that provides a user avatar URL.Default: [map[lastTransitionTime:1970-01-01T00:00:00Z message:Waiting for control plane to reconcile reason:Unknown status:Unknown type:Ready]]
false |
+
+ | lastLoginPerProvider |
+ map[string]string |
+
+ LastLoginPerProvider tracks the most recent login timestamp for each identity provider
+that the user has used to authenticate. The map key is the provider name (e.g., "github", "google")
+and the value is the RFC3339 timestamp of the last successful login via that provider.
+This field is updated by the auth provider when processing idpintent.succeeded events.
+Note: This event is only triggered during actual IDP login, not on token refresh.
+ |
+ false |
| lastLoginProvider |
string |
@@ -3836,11 +3847,23 @@ user to log in (e.g., "github" or "google"). This field is set by the auth provi
based on authentication events.
false |
+
+ | lastTokenIntrospection |
+ string |
+
+ LastTokenIntrospection records the timestamp of the most recent successful token introspection
+for this user. This is updated during authentication webhook calls when validating access tokens,
+which occurs more frequently than actual IDP logins (including token refreshes).
+The value is an RFC3339 timestamp.
+
+ Format: date-time
+ |
+ false |
| registrationApproval |
enum |
- RegistrationApproval represents the administrator’s decision on the user’s registration request.
+ RegistrationApproval represents the administrator's decision on the user's registration request.
States:
- Pending: The user is awaiting review by an administrator.
- Approved: The user registration has been approved.
diff --git a/pkg/apis/iam/v1alpha1/user_types.go b/pkg/apis/iam/v1alpha1/user_types.go
index 64825f69..32d2e234 100644
--- a/pkg/apis/iam/v1alpha1/user_types.go
+++ b/pkg/apis/iam/v1alpha1/user_types.go
@@ -106,6 +106,22 @@ type UserStatus struct {
// +kubebuilder:validation:Enum=github;google
LastLoginProvider AuthProvider `json:"lastLoginProvider,omitempty"`
+ // LastLoginPerProvider tracks the most recent login timestamp for each identity provider
+ // that the user has used to authenticate. The map key is the provider name (e.g., "github", "google")
+ // and the value is the RFC3339 timestamp of the last successful login via that provider.
+ // This field is updated by the auth provider when processing idpintent.succeeded events.
+ // Note: This event is only triggered during actual IDP login, not on token refresh.
+ // +kubebuilder:validation:Optional
+ LastLoginPerProvider map[string]string `json:"lastLoginPerProvider,omitempty"`
+
+ // LastTokenIntrospection records the timestamp of the most recent successful token introspection
+ // for this user. This is updated during authentication webhook calls when validating access tokens,
+ // which occurs more frequently than actual IDP logins (including token refreshes).
+ // The value is an RFC3339 timestamp.
+ // +kubebuilder:validation:Optional
+ // +kubebuilder:validation:Format=date-time
+ LastTokenIntrospection *metav1.Time `json:"lastTokenIntrospection,omitempty"`
+
// AvatarURL points to the avatar image associated with the user. This value is
// populated by the auth provider or any service that provides a user avatar URL.
// +kubebuilder:validation:Optional
diff --git a/pkg/apis/iam/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/iam/v1alpha1/zz_generated.deepcopy.go
index 0218d4c2..e99cbfcd 100644
--- a/pkg/apis/iam/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/iam/v1alpha1/zz_generated.deepcopy.go
@@ -1596,6 +1596,17 @@ func (in *UserStatus) DeepCopyInto(out *UserStatus) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
+ if in.LastLoginPerProvider != nil {
+ in, out := &in.LastLoginPerProvider, &out.LastLoginPerProvider
+ *out = make(map[string]string, len(*in))
+ for key, val := range *in {
+ (*out)[key] = val
+ }
+ }
+ if in.LastTokenIntrospection != nil {
+ in, out := &in.LastTokenIntrospection, &out.LastTokenIntrospection
+ *out = (*in).DeepCopy()
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserStatus.
|