(authorizationUrl: URL)
| 1850 | } |
| 1851 | |
| 1852 | async redirectToAuthorization(authorizationUrl: URL): Promise<void> { |
| 1853 | // Store the authorization URL |
| 1854 | this._authorizationUrl = authorizationUrl.toString() |
| 1855 | |
| 1856 | // Extract and store scopes from the authorization URL for later use in token exchange |
| 1857 | const scopes = authorizationUrl.searchParams.get('scope') |
| 1858 | logMCPDebug( |
| 1859 | this.serverName, |
| 1860 | `Authorization URL: ${redactSensitiveUrlParams(authorizationUrl.toString())}`, |
| 1861 | ) |
| 1862 | logMCPDebug(this.serverName, `Scopes in URL: ${scopes || 'NOT FOUND'}`) |
| 1863 | |
| 1864 | if (scopes) { |
| 1865 | this._scopes = scopes |
| 1866 | logMCPDebug( |
| 1867 | this.serverName, |
| 1868 | `Captured scopes from authorization URL: ${scopes}`, |
| 1869 | ) |
| 1870 | } else { |
| 1871 | // If no scope in URL, try to get it from metadata |
| 1872 | const metadataScope = getScopeFromMetadata(this._metadata) |
| 1873 | if (metadataScope) { |
| 1874 | this._scopes = metadataScope |
| 1875 | logMCPDebug( |
| 1876 | this.serverName, |
| 1877 | `Using scopes from metadata: ${metadataScope}`, |
| 1878 | ) |
| 1879 | } else { |
| 1880 | logMCPDebug(this.serverName, `No scopes available from URL or metadata`) |
| 1881 | } |
| 1882 | } |
| 1883 | |
| 1884 | // Persist scope for step-up auth: only when the transport-attached provider |
| 1885 | // (handleRedirection=false) receives a step-up 401. The SDK calls auth() |
| 1886 | // which calls redirectToAuthorization with the new scope. We persist it |
| 1887 | // so the next performMCPOAuthFlow can use it without an extra probe request. |
| 1888 | // Guard with !handleRedirection to avoid persisting during normal auth flows |
| 1889 | // (where the scope may come from metadata scopes_supported rather than a 401). |
| 1890 | if (this._scopes && !this.handleRedirection) { |
| 1891 | const storage = getSecureStorage() |
| 1892 | const existingData = storage.read() || {} |
| 1893 | const serverKey = getServerKey(this.serverName, this.serverConfig) |
| 1894 | const existing = existingData.mcpOAuth?.[serverKey] |
| 1895 | if (existing) { |
| 1896 | existing.stepUpScope = this._scopes |
| 1897 | storage.update(existingData) |
| 1898 | logMCPDebug(this.serverName, `Persisted step-up scope: ${this._scopes}`) |
| 1899 | } |
| 1900 | } |
| 1901 | |
| 1902 | if (!this.handleRedirection) { |
| 1903 | logMCPDebug( |
| 1904 | this.serverName, |
| 1905 | `Redirection handling is disabled, skipping redirect`, |
| 1906 | ) |
| 1907 | return |
| 1908 | } |
| 1909 |
nothing calls this directly
no test coverage detected