Repository: cloudflare/cloudflare-go
Pull request #3838 (2025-01-16 20:07:44)

AUTH-6736 Add last_seen_at to Access service token payloads
<!-- 
Provide a general summary of your changes in the title above. You should
remove this overview, any sections and any section descriptions you
don't need below before submitting. There isn't a strict requirement to
use this template if you can structure your description and still cover
these points. 
-->

## Description

Add `last_seen_at` field to Access service token payloads

<!--
Describe your changes in detail through motivation and context. Why is
this change required? What problem does it solve? If it fixes an open
issue, link to the issue using GitHub's closing issues keywords[1].
-->
## Has your change been tested?

<!--
Explain how the change has been tested and what you ran to confirm your
change affects other parts of the code. Automated tests are generally
expected and changes without tests should explain why they aren't
required.
-->

Added to unit tests

## Screenshots (if appropriate):

## Types of changes

What sort of change does your code introduce/modify?

- [ ] Bug fix (non-breaking change which fixes an issue)
- [X] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)

## Checklist:

The internal PR for updating the API docs is open and under review.

- [X] My code follows the code style of this project.
- [X] My change requires a change to the documentation.
- [X] I have updated the documentation accordingly.
- [X] I have added tests to cover my changes.
- [X] All new and existing tests passed.
- [X] This change is using publicly documented in [cloudflare/api-schemas](https://github.com/cloudflare/api-schemas) 
      and relies on stable APIs.

[1]: https://help.github.com/articles/closing-issues-using-keywords/


github-actions[bot]: Oops! It looks like no changelog entry is attached to this PR. Please include a release note as described in https://github.com/cloudflare/cloudflare-go/blob/master/docs/changelog-process.md.

Example: 

~~~
```release-note:TYPE
Release note
```
~~~

If you do not require a release note to be included, please add the `workflow/skip-changelog-entry` label.

Patch:
diff --git a/.changelog/3838.txt b/.changelog/3838.txt
new file mode 100644
index 000000000..f2de4a517
--- /dev/null
+++ b/.changelog/3838.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+access_service_token: add `last_seen_at` field
+```
diff --git a/access_service_tokens.go b/access_service_tokens.go
index 5202b2491..6fdafad1b 100644
--- a/access_service_tokens.go
+++ b/access_service_tokens.go
@@ -16,38 +16,41 @@ var (
 
 // AccessServiceToken represents an Access Service Token.
 type AccessServiceToken struct {
-	ClientID  string     `json:"client_id"`
-	CreatedAt *time.Time `json:"created_at"`
-	ExpiresAt *time.Time `json:"expires_at"`
-	ID        string     `json:"id"`
-	Name      string     `json:"name"`
-	UpdatedAt *time.Time `json:"updated_at"`
-	Duration  string     `json:"duration,omitempty"`
+	ClientID   string     `json:"client_id"`
+	CreatedAt  *time.Time `json:"created_at"`
+	ExpiresAt  *time.Time `json:"expires_at"`
+	ID         string     `json:"id"`
+	Name       string     `json:"name"`
+	UpdatedAt  *time.Time `json:"updated_at"`
+	Duration   string     `json:"duration,omitempty"`
+	LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
 }
 
 // AccessServiceTokenUpdateResponse represents the response from the API
 // when a new Service Token is updated. This base struct is also used in the
 // Create as they are very similar responses.
 type AccessServiceTokenUpdateResponse struct {
-	CreatedAt *time.Time `json:"created_at"`
-	UpdatedAt *time.Time `json:"updated_at"`
-	ExpiresAt *time.Time `json:"expires_at"`
-	ID        string     `json:"id"`
-	Name      string     `json:"name"`
-	ClientID  string     `json:"client_id"`
-	Duration  string     `json:"duration,omitempty"`
+	CreatedAt  *time.Time `json:"created_at"`
+	UpdatedAt  *time.Time `json:"updated_at"`
+	ExpiresAt  *time.Time `json:"expires_at"`
+	ID         string     `json:"id"`
+	Name       string     `json:"name"`
+	ClientID   string     `json:"client_id"`
+	Duration   string     `json:"duration,omitempty"`
+	LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
 }
 
 // AccessServiceTokenRefreshResponse represents the response from the API
 // when an existing service token is refreshed to last longer.
 type AccessServiceTokenRefreshResponse struct {
-	CreatedAt *time.Time `json:"created_at"`
-	UpdatedAt *time.Time `json:"updated_at"`
-	ExpiresAt *time.Time `json:"expires_at"`
-	ID        string     `json:"id"`
-	Name      string     `json:"name"`
-	ClientID  string     `json:"client_id"`
-	Duration  string     `json:"duration,omitempty"`
+	CreatedAt  *time.Time `json:"created_at"`
+	UpdatedAt  *time.Time `json:"updated_at"`
+	ExpiresAt  *time.Time `json:"expires_at"`
+	ID         string     `json:"id"`
+	Name       string     `json:"name"`
+	ClientID   string     `json:"client_id"`
+	Duration   string     `json:"duration,omitempty"`
+	LastSeenAt *time.Time `json:"last_seen_at,omitempty"`
 }
 
 // AccessServiceTokenCreateResponse is the same API response as the Update


Test patch:
diff --git a/access_service_tokens_test.go b/access_service_tokens_test.go
index 1f9ed8120..0e850a2ab 100644
--- a/access_service_tokens_test.go
+++ b/access_service_tokens_test.go
@@ -29,7 +29,8 @@ func TestAccessServiceTokens(t *testing.T) {
 					"id": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
 					"name": "CI/CD token",
 					"client_id": "88bf3b6d86161464f6509f7219099e57.access.example.com",
-					"duration": "8760h"
+					"duration": "8760h",
+					"last_seen_at": "2014-02-03T06:07:00.12345Z"
 				}
 			]
 		}
@@ -39,16 +40,18 @@ func TestAccessServiceTokens(t *testing.T) {
 	createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
 	updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
 	expiresAt, _ := time.Parse(time.RFC3339, "2015-01-01T05:20:00.12345Z")
+	lastSeenAt, _ := time.Parse(time.RFC3339, "2014-02-03T06:07:00.12345Z")
 
 	want := []AccessServiceToken{
 		{
-			CreatedAt: &createdAt,
-			UpdatedAt: &updatedAt,
-			ExpiresAt: &expiresAt,
-			ID:        "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
-			Name:      "CI/CD token",
-			ClientID:  "88bf3b6d86161464f6509f7219099e57.access.example.com",
-			Duration:  "8760h",
+			CreatedAt:  &createdAt,
+			UpdatedAt:  &updatedAt,
+			ExpiresAt:  &expiresAt,
+			ID:         "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
+			Name:       "CI/CD token",
+			ClientID:   "88bf3b6d86161464f6509f7219099e57.access.example.com",
+			Duration:   "8760h",
+			LastSeenAt: &lastSeenAt,
 		},
 	}
 
@@ -140,20 +143,27 @@ func TestUpdateAccessServiceToken(t *testing.T) {
 				"id": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
 				"name": "CI/CD token",
 				"client_id": "88bf3b6d86161464f6509f7219099e57.access.example.com",
-				"duration": "8760h"
+				"duration": "8760h",
+				"last_seen_at": "2014-02-03T06:07:00.12345Z"
 			}
 		}
 		`)
 	}
 
+	createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	expiresAt, _ := time.Parse(time.RFC3339, "2015-01-01T05:20:00.12345Z")
+	lastSeenAt, _ := time.Parse(time.RFC3339, "2014-02-03T06:07:00.12345Z")
+
 	expected := AccessServiceTokenUpdateResponse{
-		CreatedAt: &createdAt,
-		UpdatedAt: &updatedAt,
-		ExpiresAt: &expiresAt,
-		ID:        "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
-		Name:      "CI/CD token",
-		ClientID:  "88bf3b6d86161464f6509f7219099e57.access.example.com",
-		Duration:  "8760h",
+		CreatedAt:  &createdAt,
+		UpdatedAt:  &updatedAt,
+		ExpiresAt:  &expiresAt,
+		ID:         "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
+		Name:       "CI/CD token",
+		ClientID:   "88bf3b6d86161464f6509f7219099e57.access.example.com",
+		Duration:   "8760h",
+		LastSeenAt: &lastSeenAt,
 	}
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/access/service_tokens/f174e90a-fafe-4643-bbbc-4a0ed4fc8415", handler)
@@ -191,20 +201,27 @@ func TestRefreshAccessServiceToken(t *testing.T) {
 				"id": "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
 				"name": "CI/CD token",
 				"client_id": "88bf3b6d86161464f6509f7219099e57.access.example.com",
-				"duration": "8760h"
+				"duration": "8760h",
+				"last_seen_at": "2014-02-03T06:07:00.12345Z"
 			}
 		}
 		`)
 	}
 
+	createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z")
+	expiresAt, _ := time.Parse(time.RFC3339, "2015-01-01T05:20:00.12345Z")
+	lastSeenAt, _ := time.Parse(time.RFC3339, "2014-02-03T06:07:00.12345Z")
+
 	expected := AccessServiceTokenRefreshResponse{
-		CreatedAt: &createdAt,
-		UpdatedAt: &updatedAt,
-		ExpiresAt: &expiresAt,
-		ID:        "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
-		Name:      "CI/CD token",
-		ClientID:  "88bf3b6d86161464f6509f7219099e57.access.example.com",
-		Duration:  "8760h",
+		CreatedAt:  &createdAt,
+		UpdatedAt:  &updatedAt,
+		ExpiresAt:  &expiresAt,
+		ID:         "f174e90a-fafe-4643-bbbc-4a0ed4fc8415",
+		Name:       "CI/CD token",
+		ClientID:   "88bf3b6d86161464f6509f7219099e57.access.example.com",
+		Duration:   "8760h",
+		LastSeenAt: &lastSeenAt,
 	}
 
 	mux.HandleFunc("/accounts/"+testAccountID+"/access/service_tokens/f174e90a-fafe-4643-bbbc-4a0ed4fc8415/refresh", handler)