title: Unable to push nuGet packages to GitLab with dotnet CLI due to Unauthorized error
body: <p>GitLab now supports nuget public and private feed repository.
  I've got a public project (e.g: <a href="https://gitlab.com/sunnyatticsoftware/sasw-test-support" rel="nofollow noreferrer">https://gitlab.com/sunnyatticsoftware/sasw-test-support</a>)
  I create an access token for my user with <code>api</code> and <code>write_repository</code> (e.g: AAABBBCCCDDD)</p>
  <p>I create a group variable in my CI/CD: <code>SASW_API_ACCESS_TOKEN</code>: <code>AAABBBCCCDDD</code>. All normal.</p>
  <p>Then I create the multi stage CI/CD script to build, pack and publish.
  When attempting to publish the nuGet package with the following:
  <code>dotnet nuget push **/*.nupkg --source https://gitlab.com/api/v4/projects/17141695/packages/nuget/index.json --api-key AAABBBCCCDDD --skip-duplicate</code></p>
  <p>I get the error:</p>
  <pre><code>info : Pushing Sasw.TestSupport.2.0.2.nupkg to 'https://gitlab.com/api/v4/projects/17141695/packages/nuget'...
  info :   PUT https://gitlab.com/api/v4/projects/17141695/packages/nuget/
  info :   Unauthorized https://gitlab.com/api/v4/projects/17141695/packages/nuget/ 397ms
  error: Response status code does not indicate success: 401 (Unauthorized).
  ERROR: Job failed: exit code 1
  </code></pre>
  <p>The <a href="https://docs.gitlab.com/ee/user/packages/nuget_repository/" rel="nofollow noreferrer">documentation</a> doesn't mention anything special, but I notice that when using the (legacy?) nuget CLI it passes a username. Dotnet CLI, however, doesn't support username, just API KEY.</p>
  <p>Any idea why this is not working?</p>
  <p>This is my CI/CD script:</p>
  <pre><code>variables:
    GITLAB_RUNNER_DOTNET_CORE: mcr.microsoft.com/dotnet/core/sdk:3.1
    NUGET_REPOSITORY: https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/packages/nuget/index.json
    NUGET_API_KEY: $SASW_API_ACCESS_TOKEN
    NUGET_FOLDER_NAME: nupkgs
    NUGET_VERSION_SUFFIX: $SASW_PRERELEASE_SUFFIX
  
  stages:
    - build
    - pack
    - release
    
  #Docker image
  image: $GITLAB_RUNNER_DOTNET_CORE
  
  #Jobs
  ci:
    stage: build
    script:
      - dotnet restore --no-cache --force
      - dotnet build --configuration Release --no-restore
      #- dotnet vstest test/*UnitTests/bin/Release/**/*UnitTests.dll
      #- dotnet vstest test/*IntegrationTests/bin/Release/**/*IntegrationTests.dll
      
  pack-prerelease:
    stage: pack
    script:
      - dotnet pack *.sln --configuration Release --output $NUGET_FOLDER_NAME --version-suffix $NUGET_VERSION_SUFFIX --include-symbols -p:SymbolPackageFormat=snupkg
    artifacts:
      paths:
      - $NUGET_FOLDER_NAME
      expire_in: 1 week
    except:
      - master
  
  pack-release:
    stage: pack
    script:
      - dotnet pack *.sln --configuration Release --output $NUGET_FOLDER_NAME
    artifacts:
      paths:
      - $NUGET_FOLDER_NAME
      expire_in: 1 week
    only:
      - master
  
  publish-nuget:
    stage: release
    script:
      - dotnet nuget push **/*.nupkg --source $NUGET_REPOSITORY --api-key $NUGET_API_KEY --skip-duplicate
  </code></pre>
  <p>PS: The project is public, so in case it's needed have a look at: <a href="https://gitlab.com/sunnyatticsoftware/sasw-test-support/-/jobs/451080235" rel="nofollow noreferrer">https://gitlab.com/sunnyatticsoftware/sasw-test-support/-/jobs/451080235</a></p>
  <hr />
  <p>UPDATE 1: Further verbosity from my local linux console</p>
  <pre><code>$ dotnet nuget -v Debug push **/*.nupkg --source https://gitlab.com/api/v4/projects/17141695/packages/nuget/index.json --api-key cBwt5_hidden_ --skip-duplicate
  trace: NuGet Command Line Version: 5.4.0.2
  info : Pushing Sasw.TestSupport.2.0.2.nupkg to 'https://gitlab.com/api/v4/projects/17141695/packages/nuget'...
  info :   PUT https://gitlab.com/api/v4/projects/17141695/packages/nuget/
  info :   Unauthorized https://gitlab.com/api/v4/projects/17141695/packages/nuget/ 1159ms
  error: Response status code does not indicate success: 401 (Unauthorized).
  trace: System.AggregateException: One or more errors occurred. (Response status code does not indicate success: 401 (Unauthorized).)
  trace:  ---&gt; System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized).
  trace:    at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
  trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.EnsureSuccessStatusCode(HttpResponseMessage response, Nullable`1 codeNotToThrow, ILogger logger)
  trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.&lt;&gt;c__DisplayClass23_0.&lt;PushPackageToServer&gt;b__0(HttpResponseMessage response)
  trace:    at NuGet.Protocol.HttpSource.ProcessResponseAsync[T](HttpSourceRequest request, Func`2 processAsync, SourceCacheContext cacheContext, ILogger log, CancellationToken token)
  trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.PushPackageToServer(String source, String apiKey, String pathToPackage, Int64 packageSize, Boolean noServiceEndpoint, Boolean skipDuplicate, TimeSpan requestTimeout, ILogger logger, CancellationToken token)
  trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.PushPackageCore(String source, String apiKey, String packageToPush, Boolean noServiceEndpoint, Boolean skipDuplicate, TimeSpan requestTimeout, ILogger log, CancellationToken token)
  trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.PushPackage(String packagePath, String source, String apiKey, Boolean noServiceEndpoint, Boolean skipDuplicate, TimeSpan requestTimeout, ILogger log, CancellationToken token, Boolean isSnupkgPush)
  trace:    at NuGet.Protocol.Core.Types.PackageUpdateResource.Push(String packagePath, String symbolSource, Int32 timeoutInSecond, Boolean disableBuffering, Func`2 getApiKey, Func`2 getSymbolApiKey, Boolean noServiceEndpoint, Boolean skipDuplicate, SymbolPackageUpdateResourceV3 symbolPackageUpdateResource, ILogger log)
  trace:    at NuGet.Commands.PushRunner.Run(ISettings settings, IPackageSourceProvider sourceProvider, String packagePath, String source, String apiKey, String symbolSource, String symbolApiKey, Int32 timeoutSeconds, Boolean disableBuffering, Boolean noSymbols, Boolean noServiceEndpoint, Boolean skipDuplicate, ILogger logger)
  trace:    at NuGet.CommandLine.XPlat.PushCommand.&lt;&gt;c__DisplayClass0_1.&lt;&lt;Register&gt;b__1&gt;d.MoveNext()
  trace:    --- End of inner exception stack trace ---
  trace:    at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
  trace:    at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
  trace:    at System.Threading.Tasks.Task`1.get_Result()
  trace:    at Microsoft.Extensions.CommandLineUtils.CommandLineApplication.&lt;&gt;c__DisplayClass56_0.&lt;OnExecute&gt;b__0()
  trace:    at Microsoft.Extensions.CommandLineUtils.CommandLineApplication.Execute(String[] args)
  trace:    at NuGet.CommandLine.XPlat.Program.MainInternal(String[] args, CommandOutputLogger log)
  
  </code></pre>
  <p>UPDATE 2: Alexey's answer is the proper one and up to date as per April 2021. GitLab has improved Nuget support in the last year and now it's possible to easily push packages to the repo package registry and have readacces on Nuget feed at project level or group level using deploy tokens.</p>