-
Notifications
You must be signed in to change notification settings - Fork 1.3k
fix: Prefer the token_endpoint_auth_method
response from DCR registration
#982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,6 @@ import pkceChallenge from "pkce-challenge"; | |
import { LATEST_PROTOCOL_VERSION } from "../types.js"; | ||
import { | ||
OAuthClientMetadata, | ||
OAuthClientInformation, | ||
OAuthTokens, | ||
OAuthMetadata, | ||
OAuthClientInformationFull, | ||
|
@@ -51,7 +50,7 @@ export interface OAuthClientProvider { | |
* server, or returns `undefined` if the client is not registered with the | ||
* server. | ||
*/ | ||
clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>; | ||
clientInformation(): OAuthClientInformationFull | undefined | Promise<OAuthClientInformationFull | undefined>; | ||
|
||
/** | ||
* If implemented, this permits the OAuth client to dynamically register with | ||
|
@@ -139,6 +138,10 @@ export class UnauthorizedError extends Error { | |
|
||
type ClientAuthMethod = 'client_secret_basic' | 'client_secret_post' | 'none'; | ||
|
||
function isClientAuthMethod(method: string): method is ClientAuthMethod { | ||
return ["client_secret_basic", "client_secret_post", "none"].includes(method); | ||
} | ||
|
||
/** | ||
* Determines the best client authentication method to use based on server support and client configuration. | ||
* | ||
|
@@ -152,7 +155,7 @@ type ClientAuthMethod = 'client_secret_basic' | 'client_secret_post' | 'none'; | |
* @returns The selected authentication method | ||
*/ | ||
function selectClientAuthMethod( | ||
clientInformation: OAuthClientInformation, | ||
clientInformation: OAuthClientInformationFull, | ||
supportedMethods: string[] | ||
): ClientAuthMethod { | ||
const hasClientSecret = clientInformation.client_secret !== undefined; | ||
|
@@ -162,6 +165,15 @@ function selectClientAuthMethod( | |
return hasClientSecret ? "client_secret_post" : "none"; | ||
} | ||
|
||
// Prefer the method returned by the server during client registration if valid and supported | ||
if ( | ||
clientInformation.token_endpoint_auth_method && | ||
isClientAuthMethod(clientInformation.token_endpoint_auth_method) && | ||
supportedMethods.includes(clientInformation.token_endpoint_auth_method) | ||
) { | ||
return clientInformation.token_endpoint_auth_method; | ||
} | ||
|
||
Comment on lines
+168
to
+176
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this throw an error if an invalid or unsupported On the other hand, should it even care if it's valid or supported in this context? or should it just use the |
||
// Try methods in priority order (most secure first) | ||
if (hasClientSecret && supportedMethods.includes("client_secret_basic")) { | ||
return "client_secret_basic"; | ||
|
@@ -195,7 +207,7 @@ function selectClientAuthMethod( | |
*/ | ||
function applyClientAuthentication( | ||
method: ClientAuthMethod, | ||
clientInformation: OAuthClientInformation, | ||
clientInformation: OAuthClientInformationFull, | ||
headers: Headers, | ||
params: URLSearchParams | ||
): void { | ||
|
@@ -809,7 +821,7 @@ export async function startAuthorization( | |
resource, | ||
}: { | ||
metadata?: AuthorizationServerMetadata; | ||
clientInformation: OAuthClientInformation; | ||
clientInformation: OAuthClientInformationFull; | ||
redirectUrl: string | URL; | ||
scope?: string; | ||
state?: string; | ||
|
@@ -902,7 +914,7 @@ export async function exchangeAuthorization( | |
fetchFn, | ||
}: { | ||
metadata?: AuthorizationServerMetadata; | ||
clientInformation: OAuthClientInformation; | ||
clientInformation: OAuthClientInformationFull; | ||
authorizationCode: string; | ||
codeVerifier: string; | ||
redirectUri: string | URL; | ||
|
@@ -988,7 +1000,7 @@ export async function refreshAuthorization( | |
fetchFn, | ||
}: { | ||
metadata?: AuthorizationServerMetadata; | ||
clientInformation: OAuthClientInformation; | ||
clientInformation: OAuthClientInformationFull; | ||
refreshToken: string; | ||
resource?: URL; | ||
addClientAuthentication?: OAuthClientProvider["addClientAuthentication"]; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the
redirect_uris
to all the mock objects to match the new typeOAuthClientInformationFull