diff --git a/src/DPoPTokenProvider.ts b/src/DPoPTokenProvider.ts index 5efc748..4e1b84c 100644 --- a/src/DPoPTokenProvider.ts +++ b/src/DPoPTokenProvider.ts @@ -4,6 +4,7 @@ import type { CodeProvider } from "./CodeProvider.js" import type { TokenProvider } from "./TokenProvider.js" import type { AuthorizationServerProvider } from "./AuthorizationServerProvider.js" import { ClientProvider } from "./ClientProvider.js" +import { supportsOfflineAccess } from "./supportsOfflineAccess.js" type CacheEntry = { created: number, tokenResult: oauth.TokenEndpointResponse, dpopKey: CryptoKeyPair } @@ -54,11 +55,16 @@ export class DPoPTokenProvider implements TokenProvider { const nonce = oauth.generateRandomNonce() const state = oauth.generateRandomState() + const scopes = ["openid", "webid"] + if (supportsOfflineAccess(authorizationServer)) { + scopes.push("offline_access") + } + const authorizationUrl = new URL(authorizationServer.authorization_endpoint!) authorizationUrl.searchParams.set("client_id", clientRegistration.client_id) authorizationUrl.searchParams.set("redirect_uri", registeredRedirectUri!) authorizationUrl.searchParams.set("response_type", registeredResponseType!) - authorizationUrl.searchParams.set("scope", "openid webid") + authorizationUrl.searchParams.set("scope", scopes.join(" ")) authorizationUrl.searchParams.set("prompt", "none") authorizationUrl.searchParams.set("state", state) authorizationUrl.searchParams.set("nonce", nonce) diff --git a/src/DynamicRegistrationClientProvider.ts b/src/DynamicRegistrationClientProvider.ts index f3ecd56..1365e8b 100644 --- a/src/DynamicRegistrationClientProvider.ts +++ b/src/DynamicRegistrationClientProvider.ts @@ -1,9 +1,19 @@ import type { ClientProvider } from "./ClientProvider.js" import * as oauth from "oauth4webapi" +import { supportsOfflineAccess } from "./supportsOfflineAccess.js" export class DynamicRegistrationClientProvider implements ClientProvider { async getClient(as: oauth.AuthorizationServer, redirectUri: string, signal: AbortSignal): Promise { - const registrationResponse = await oauth.dynamicClientRegistrationRequest(as, {redirect_uris: [redirectUri]}, {signal}) + const metadata = { + redirect_uris: [redirectUri], + grant_types: ["authorization_code"] + } + + if (supportsOfflineAccess(as)) { + metadata.grant_types.push("refresh_token") + } + + const registrationResponse = await oauth.dynamicClientRegistrationRequest(as, metadata, {signal}) const client = await oauth.processDynamicClientRegistrationResponse(registrationResponse) return client diff --git a/src/mod.ts b/src/mod.ts index 851b4d7..c704f1b 100644 --- a/src/mod.ts +++ b/src/mod.ts @@ -21,4 +21,5 @@ export * from "./CachingAuthorizationServerProvider.js" export * from "./ClientProvider.js" export * from "./DynamicRegistrationClientProvider.js" export * from "./CachingClientProvider.js" +export * from "./supportsOfflineAccess.js" export * from "./ClientIdClientProvider.js" diff --git a/src/supportsOfflineAccess.ts b/src/supportsOfflineAccess.ts new file mode 100644 index 0000000..4c9be8f --- /dev/null +++ b/src/supportsOfflineAccess.ts @@ -0,0 +1,5 @@ +import * as oauth from "oauth4webapi" + +export function supportsOfflineAccess(as: oauth.AuthorizationServer) { + return as.scopes_supported === undefined || as.scopes_supported.includes("offline_access") +}