From 2ddac1619f333d9e9b7984dfe86d88d7051709d8 Mon Sep 17 00:00:00 2001 From: Samuel Elliott Date: Fri, 1 Aug 2025 21:29:04 +0100 Subject: [PATCH] Fix unable to fetch web service tokens in app --- src/api/coral.ts | 3 ++- src/api/f.ts | 10 +++++++++- src/cli.ts | 3 ++- src/cli/nxapi-auth/link-url.ts | 9 +-------- src/util/nxapi-auth.ts | 2 ++ 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/api/coral.ts b/src/api/coral.ts index f5f1615..6a05d67 100644 --- a/src/api/coral.ts +++ b/src/api/coral.ts @@ -919,7 +919,8 @@ class CoralApiRequest { const decrypted = request_encryption instanceof ZncaApiNxapi ? await request_encryption.decryptResponse(data, - this.flags[RequestFlagNxapiZncaApiRequestNsaAssertionSymbol]) : + request_encryption.auth?.has_nsa_assertion_scope && + this.flags[RequestFlagNxapiZncaApiRequestNsaAssertionSymbol]) : await request_encryption.decryptResponse(data); const encryption: ResponseEncryption = { diff --git a/src/api/f.ts b/src/api/f.ts index 3616872..b680efe 100644 --- a/src/api/f.ts +++ b/src/api/f.ts @@ -554,7 +554,7 @@ export class NxapiZncaAuth { { id: string; secret: string; } | { id: string; } | null = null; - + request_scope = 'ca:gf ca:er ca:dr'; token: TokenData | null = null; @@ -626,6 +626,13 @@ export class NxapiZncaAuth { return !!this.token && this.token.expires_at > Date.now(); } + get has_nsa_assertion_scope() { + return this.token?.result.scope ? !!this.token.result.scope.match(/\bca:ns\b/) : + this.client_assertion_provider && !this.client_credentials ? + !!this.client_assertion_provider.scope.match(/\bca:ns\b/) : + this.client_credentials ? !!this.request_scope.match(/\bca:ns\b/) : false; + } + async getAccessToken(): Promise { const resource = this.protected_resource ?? (this.protected_resource = await this.getProtectedResource()); const refresh_token = this.refresh_token; @@ -658,6 +665,7 @@ export class NxapiZncaAuth { body.append('client_assertion_type', type); body.append('client_assertion', assertion); + body.set('scope', this.client_assertion_provider.scope); } else { if (resource.resource_metadata.resource_documentation) { throw new TypeError('Client authentication not configured\n\n' + diff --git a/src/cli.ts b/src/cli.ts index 9d8f1f5..7a6ffd8 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -59,7 +59,8 @@ export async function main(argv = process.argv.slice(2)) { addUserAgent('unidentified-script'); } - setClientAssertionProvider(new ClientAssertionProvider(NXAPI_AUTH_CLI_CLIENT_ID)); + setClientAssertionProvider(new ClientAssertionProvider(NXAPI_AUTH_CLI_CLIENT_ID, undefined, + 'ca:gf ca:er ca:dr ca:na')); const yargs = createYargs(argv); diff --git a/src/cli/nxapi-auth/link-url.ts b/src/cli/nxapi-auth/link-url.ts index 3f2fabe..16601aa 100644 --- a/src/cli/nxapi-auth/link-url.ts +++ b/src/cli/nxapi-auth/link-url.ts @@ -1,4 +1,4 @@ -import type { Arguments as ParentArguments } from '../nso/index.js'; +import type { Arguments as ParentArguments } from './index.js'; import createDebug from '../../util/debug.js'; import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js'; import { initStorage } from '../../util/storage.js'; @@ -32,13 +32,6 @@ export async function handler(argv: ArgumentsCamelCase) { throw new Error('API proxy not supported'); } - if (!process.env.NXAPI_ZNCA_API_AUTH_SCOPE) { - // TODO: default cli/app clients should have this scope set automatically - // - custom clients won't be able to request this scope though so can't - // just be the default request scope - process.env.NXAPI_ZNCA_API_AUTH_SCOPE = 'ca:gf ca:er ca:dr ca:na'; - } - const storage = await initStorage(argv.dataPath); const user_na_id = argv.user ?? await storage.getItem('SelectedUser'); diff --git a/src/util/nxapi-auth.ts b/src/util/nxapi-auth.ts index c6b3503..7c02a88 100644 --- a/src/util/nxapi-auth.ts +++ b/src/util/nxapi-auth.ts @@ -12,6 +12,7 @@ export function setClientAssertionProvider(provider: ClientAssertionProviderInte } export interface ClientAssertionProviderInterface { + scope: string; create(aud: string, exp?: number): Promise; } export interface OAuthClientAssertion { @@ -24,6 +25,7 @@ export class ClientAssertionProvider implements ClientAssertionProviderInterface readonly client_id: string, // readonly iss = 'nxapi', readonly iss = client_id, + public scope = 'ca:gf ca:er ca:dr', ) {} async create(aud: string, exp = 60) {