Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions clients/go/ahptypes/notifications.generated.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,16 +138,16 @@ type ProgressParams struct {
// This notification MAY be associated with any channel — for example, an
// agent advertised on the root channel, or a per-session resource. The
// `channel` field identifies the subscription the auth requirement belongs
// to; the `resource` field carries the OAuth-protected resource identifier
// (per RFC 9728).
// to; the `resource` field carries the complete OAuth protected resource
// metadata (per RFC 9728).
//
// Clients should obtain a fresh token and push it via the `authenticate`
// command.
type AuthRequiredParams struct {
// Channel URI this notification belongs to
Channel URI `json:"channel"`
// The protected resource identifier that requires authentication
Resource string `json:"resource"`
// Complete RFC 9728 metadata for the protected resource that requires authentication
Resource ProtectedResourceMetadata `json:"resource"`
// Why authentication is required
Reason *AuthRequiredReason `json:"reason,omitempty"`
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ data class AuthRequiredParams(
*/
val channel: String,
/**
* The protected resource identifier that requires authentication
* Complete RFC 9728 metadata for the protected resource that requires authentication
*/
val resource: String,
val resource: ProtectedResourceMetadata,
/**
* Why authentication is required
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,15 @@ class GeneratedStructsTest {

val authWire = """{
"channel": "ahp-root://",
"resource": "https://api.github.com",
"resource": {
"resource": "https://api.github.com",
"authorization_servers": ["https://github.com/login/oauth"]
},
"reason": "expired"
}""".trimIndent()
val auth = json.decodeFromString(AuthRequiredParams.serializer(), authWire)
assertEquals("ahp-root://", auth.channel)
assertEquals("https://api.github.com", auth.resource)
assertEquals("https://api.github.com", auth.resource.resource)
}

@Test
Expand Down
10 changes: 5 additions & 5 deletions clients/rust/crates/ahp-types/src/notifications.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use serde_repr::{Deserialize_repr, Serialize_repr};
#[allow(unused_imports)]
use crate::state::{
AgentSelection, AnnotationsSummary, ChangesSummary, Changeset, FileEdit, ModelSelection,
ProjectInfo, SessionStatus, SessionSummary,
ProjectInfo, ProtectedResourceMetadata, SessionStatus, SessionSummary,
};

// ─── Enums ────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -153,8 +153,8 @@ pub struct ProgressParams {
/// This notification MAY be associated with any channel — for example, an
/// agent advertised on the root channel, or a per-session resource. The
/// `channel` field identifies the subscription the auth requirement belongs
/// to; the `resource` field carries the OAuth-protected resource identifier
/// (per RFC 9728).
/// to; the `resource` field carries the complete OAuth protected resource
/// metadata (per RFC 9728).
///
/// Clients should obtain a fresh token and push it via the `authenticate`
/// command.
Expand All @@ -163,8 +163,8 @@ pub struct ProgressParams {
pub struct AuthRequiredParams {
/// Channel URI this notification belongs to
pub channel: Uri,
/// The protected resource identifier that requires authentication
pub resource: String,
/// Complete RFC 9728 metadata for the protected resource that requires authentication
pub resource: ProtectedResourceMetadata,
/// Why authentication is required
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reason: Option<AuthRequiredReason>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ public struct ProgressParams: Codable, Sendable {
public struct AuthRequiredParams: Codable, Sendable {
/// Channel URI this notification belongs to
public var channel: String
/// The protected resource identifier that requires authentication
public var resource: String
/// Complete RFC 9728 metadata for the protected resource that requires authentication
public var resource: ProtectedResourceMetadata
/// Why authentication is required
public var reason: AuthRequiredReason?

public init(
channel: String,
resource: String,
resource: ProtectedResourceMetadata,
reason: AuthRequiredReason? = nil
) {
self.channel = channel
Expand Down
4 changes: 4 additions & 0 deletions docs/.changes/20260812-auth-required-resource-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"type": "changed",
"message": "`auth/required` now carries complete `ProtectedResourceMetadata` in its required `resource` field."
}
9 changes: 7 additions & 2 deletions docs/specification/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,18 @@ The server MAY send an [`auth/required`](/reference/common#authrequired) notific
"method": "auth/required",
"params": {
"channel": "ahp-root://",
"resource": "https://api.github.com",
"resource": {
"resource": "https://api.github.com",
"resource_name": "GitHub Copilot",
"authorization_servers": ["https://github.com/login/oauth"],
"scopes_supported": ["read:user", "user:email"]
},
"reason": "expired"
}
}
```

The `reason` field indicates why authentication is required:
The `resource` field carries the complete [`ProtectedResourceMetadata`](/reference/common#protectedresourcemetadata) object for the resource that requires authentication. The `reason` field indicates why authentication is required:

| Value | Description |
|---|---|
Expand Down
6 changes: 3 additions & 3 deletions schema/notifications.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
"$defs": {
"AuthRequiredParams": {
"type": "object",
"description": "Sent by the server when a protected resource requires (re-)authentication.\n\nThis notification MAY be associated with any channel — for example, an\nagent advertised on the root channel, or a per-session resource. The\n`channel` field identifies the subscription the auth requirement belongs\nto; the `resource` field carries the OAuth-protected resource identifier\n(per RFC 9728).\n\nClients should obtain a fresh token and push it via the `authenticate`\ncommand.",
"description": "Sent by the server when a protected resource requires (re-)authentication.\n\nThis notification MAY be associated with any channel — for example, an\nagent advertised on the root channel, or a per-session resource. The\n`channel` field identifies the subscription the auth requirement belongs\nto; the `resource` field carries the complete OAuth protected resource\nmetadata (per RFC 9728).\n\nClients should obtain a fresh token and push it via the `authenticate`\ncommand.",
"properties": {
"channel": {
"$ref": "#/$defs/URI",
"description": "Channel URI this notification belongs to"
},
"resource": {
"type": "string",
"description": "The protected resource identifier that requires authentication"
"$ref": "#/$defs/ProtectedResourceMetadata",
"description": "Complete RFC 9728 metadata for the protected resource that requires authentication"
},
"reason": {
"$ref": "#/$defs/AuthRequiredReason",
Expand Down
2 changes: 1 addition & 1 deletion scripts/generate-rust.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1611,7 +1611,7 @@ const NOTIFICATION_STRUCTS = [
function generateNotificationsFile(project: Project): string {
const lines: string[] = [GENERATED_HEADER];
lines.push('#[allow(unused_imports)]');
lines.push('use crate::state::{AgentSelection, AnnotationsSummary, ChangesSummary, Changeset, FileEdit, ModelSelection, ProjectInfo, SessionStatus, SessionSummary};');
lines.push('use crate::state::{AgentSelection, AnnotationsSummary, ChangesSummary, Changeset, FileEdit, ModelSelection, ProjectInfo, ProtectedResourceMetadata, SessionStatus, SessionSummary};');
lines.push('');

lines.push('// ─── Enums ────────────────────────────────────────────────────────────\n');
Expand Down
16 changes: 10 additions & 6 deletions types/common/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* @module common/notifications
*/

import type { URI } from './state.js';
import type { ProtectedResourceMetadata, URI } from './state.js';

/**
* Reason why authentication is required.
Expand All @@ -27,8 +27,8 @@ export const enum AuthRequiredReason {
* This notification MAY be associated with any channel — for example, an
* agent advertised on the root channel, or a per-session resource. The
* `channel` field identifies the subscription the auth requirement belongs
* to; the `resource` field carries the OAuth-protected resource identifier
* (per RFC 9728).
* to; the `resource` field carries the complete OAuth protected resource
* metadata (per RFC 9728).
*
* Clients should obtain a fresh token and push it via the `authenticate`
* command.
Expand All @@ -46,7 +46,11 @@ export const enum AuthRequiredReason {
* "method": "auth/required",
* "params": {
* "channel": "ahp-root://",
* "resource": "https://api.github.com",
* "resource": {
* "resource": "https://api.github.com",
* "resource_name": "GitHub API",
* "authorization_servers": ["https://github.com/login/oauth"]
* },
* "reason": "expired"
* }
* }
Expand All @@ -55,8 +59,8 @@ export const enum AuthRequiredReason {
export interface AuthRequiredParams {
/** Channel URI this notification belongs to */
channel: URI;
/** The protected resource identifier that requires authentication */
resource: string;
/** Complete RFC 9728 metadata for the protected resource that requires authentication */
resource: ProtectedResourceMetadata;
/** Why authentication is required */
reason?: AuthRequiredReason;
}
Loading