Skip to content

OCI Authentication Hardcoded for Azure #1946

Description

Prerequisites

  • Write a descriptive title.
  • Make sure you are able to repro it on the latest released version
  • Search the existing issues.

Steps to reproduce

The authentication mechanisms used on OCI/Container Registries is essentially hardcoded to only work for ACR based registries. This makes it impossible to use PSResourceGet with other OCI registries that don't follow the ACR specific auth flow.

For example it is not possible to install from GitHub's Container/OCI repository. I've got a test nupkg published at https://github.com/jborean93/PowerShell-PublishTest/pkgs/container/publishtest and this is what happens when you try to install it with and without a credential with PSResourceGet 1.2.0-rc3

Register-PSResourceRepository -Name GHCR -Uri https://ghcr.io -ApiVersion ContainerRegistry

# Try it with anonymous access/no credential
Install-PSResource -Name jborean93/publishtest -Repository GHCR -Debug -Verbose -TrustRepository
$Error[1] | Select-Object *
DEBUG: Package version parsed as NuGet version: '1.2.0-rc3'
DEBUG: Reading package metadata from: '/home/jborean/.local/share/powershell/Modules/Microsoft.PowerShell.PSResourceGet/1.2.0/PSGetModuleInfo.xml'
DEBUG: In InstallPSResource::ProcessInstallHelper()
DEBUG: In InstallHelper::BeginInstallPackages()
DEBUG: Parameters passed in >>> Name: 'jborean93/publishtest'; VersionRange: ''; NuGetVersion: ''; VersionType: 'NoVersion'; Version: ''; Prerelease: 'False'; Repository: 'GHCR'; AcceptLicense: 'False'; Quiet: 'False'; Reinstall: 'False'; TrustRepository: 'True'; NoClobber: 'False'; AsNupkg: 'False'; IncludeXml 'True'; SavePackage 'False'; TemporaryPath ''; SkipDependencyCheck: 'False'; AuthenticodeCheck: 'False'; PathsToInstallPkg: '/home/jborean/.local/share/powershell/Modules,/home/jborean/.local/share/powershell/Scripts'; Scope 'CurrentUser'
DEBUG: In InstallHelper::ProcessRepositories()
VERBOSE: Setting Secret Management network credentials
VERBOSE: Attempting to search for packages in 'GHCR'
DEBUG: In InstallHelper::InstallPackages()
DEBUG: In InstallHelper::InstallPackage()
DEBUG: In ContainerRegistryServerAPICalls::FindName()
DEBUG: In ContainerRegistryServerAPICalls::FindPackagesWithVersionHelper()
DEBUG: In ContainerRegistryServerAPICalls::GetContainerRegistryAccessToken()
DEBUG: In ContainerRegistryServerAPICalls::IsContainerRegistryUnauthenticated()
DEBUG: Is repository unauthenticated: False
DEBUG: In ContainerRegistryServerAPICalls::GetContainerRegistryRefreshToken()
DEBUG: In ContainerRegistryServerAPICalls::GetHttpResponseJObjectUsingContentHeaders()
Install-PSResource: Response returned error with status code MethodNotAllowed: Method Not Allowed.
VERBOSE: Attempting to delete '/tmp/a36c194f-1a8b-4239-8ec3-ae8c0e2f5038'
VERBOSE: Successfully deleted '/tmp/a36c194f-1a8b-4239-8ec3-ae8c0e2f5038'
Install-PSResource: Package(s) 'jborean93/publishtest' could not be installed from repository 'GHCR'.

# $Error[1]
PSMessageDetails      : 
Exception             : System.Exception: Response returned error with status code MethodNotAllowed: Method Not Allowed.
                           at Microsoft.PowerShell.PSResourceGet.ContainerRegistryServerAPICalls.SendRequestAsync(HttpRequestMessage 
                        message) in C:\__w\1\s\PSResourceGet\src\code\ContainerRegistryServerAPICalls.cs:line 1170
                           at Microsoft.PowerShell.PSResourceGet.ContainerRegistryServerAPICalls.GetHttpResponseJObjectUsingContentHead
                        ers(String url, HttpMethod method, String content, Collection`1 contentHeaders, ErrorRecord& errRecord) in 
                        C:\__w\1\s\PSResourceGet\src\code\ContainerRegistryServerAPICalls.cs:line 1045
TargetObject          : Microsoft.PowerShell.PSResourceGet.Cmdlets.InstallPSResource
CategoryInfo          : InvalidResult: (Microsoft.PowerShel…s.InstallPSResource:InstallPSResource) [Install-PSResource], Exception
FullyQualifiedErrorId : HttpRequestCallFailure,Microsoft.PowerShell.PSResourceGet.Cmdlets.InstallPSResource
ErrorDetails          : 
InvocationInfo        : System.Management.Automation.InvocationInfo
ScriptStackTrace      : at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {0, 1}

The same error occurs when you use a -Credential with a GitHub username/PAT. The error may vary depending on whether there is an Az context available as PSResourceGet falls back on this for all registries.

The reason is because GetContainerRegistryAccessToken is coded to do the following

  • Use a cached token from a previous request (not applicable here)
  • Retrieve the Azure AccessToken and TenantId from the SecretStore if a credential is set on the registered repository (not applicable here)
  • Checks if the registry allows unauthenticated requests (false here)
    • The logic for getting an anonymous token is also ACR specific and won't work for other OCI repositories
  • Fallback to getting the Az Access Token from DefaultAzureCredential
    • If none available it will fail here
    • In my case I do have an az token available
  • If we have an Az AccessToken from SecureStore or the environment use an ACR OAuth2 flow to get the ACR bearer token
    • This auth flow is ACR specific and fails with the error you see above
  • If not AccessToken then it fails

The 3 problems I see here

  • The anonymous token workflow needs to be updated to work generically
  • The oauth2/exchange workflow that ultimately gets the ACR bearer token from an Az AccessToken needs to be selectively done (some flag on the registered repository maybe?)
  • If a credential is passed in then the oauth2/exchange flow should not be done unless
    • The incoming credential is an Az AccessToken from something like Get-AzAccessToken
    • Not if its an Azure client id and secret as that is just used directly in the token exchange

I'm hoping to send through a PR to try and fix this at least for some of the scenarios but wanted to raise the issue to at least summarise what is happening. I've written Get-OciBearerToken to show the workflow that I've found works for ACR, MAR, GHCR, and hopefully any other OCI compliant registry. I've used this function to

  • push a new package for ACR, GHCR
    • GHCR uses the GitHub username and PAT with write:packages set or through the GHA GITHUB_TOKEN value
    • ACR can use an app client_id and secret value directly
    • ACR can use the AccessToken returned by Get-AzAccessToken for any valid connection using the oauth2/exchange to get the ACR refresh token
  • pull from ACR, MAR, GHDR
    • Using anonymous access
    • With the same credential as push

The biggest hiccup is figuring out whether we have an Az AccessToken to do the oauth2/exchange step.

Expected behavior

Module can be installed with no credential when the registry allows it or with a credential when it is private.

Actual behavior

See above (fails)

Error details

See above

Environment data

ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Binary     1.2.0      rc3        Microsoft.PowerShell.PSResourceGet  {Compress-PSResource, Find-PSResource, Get-InstalledPSResource, G…


Name                           Value
----                           -----
PSVersion                      7.5.1
PSEdition                      Core
GitCommitId                    7.5.1
OS                             Fedora Linux 43 (Server Edition)
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

Activity

  1. jborean93 commented on Feb 20, 2026

    @jborean93
    Author

    This also brings into question around what the credential type is expected to be in a SecretManagement store. Right now it expects a credential in the form of tenantId and the Az AccessToken and will do the oauth2/exchange flow to get the ACR refresh token from that. This isn't ideal as

    • It's ACR specific so any other OCI registries cannot store a token in the repository registration
    • The access token is short lived which defeats the purpose of persisting such a value over time

    It seems like this logic should change so that the credential stored here is used directly with the bearer token exchange like

    # The user/pass is dependent on the registry but it's typically a user + secret
    # GHCR is username:path_token
    # ACR is client_id:client_secret
    $secretCred = Get-Secret ...
    
    $registry = "ghcr.io"
    $scope = "repository:jborean93/publishtest:pull"
    $registryUri = "https://$Registry/v2/"
    $resp = Invoke-WebRequest -Uri $registryUri -SkipHttpErrorCheck
    $bearer = $resp.Headers['WWW-Authenticate'] | Select-Object -First 1
    if (-not $bearer) {
        throw "No WWW-Authenticate found in response headers for '$registryUri'"
    }
    
    if ($bearer -match 'realm="([^"]+)"') {
        $realm = $matches[1]
    } else {
        throw "Could not extract realm from WWW-Authenticate header '$bearer'"
    }
    
    if ($bearer -match 'service="([^"]+)"') {
        $service = $matches[1]
    } else {
        throw "Could not extract service from WWW-Authenticate header '$bearer'"
    }
    
    $tokenUri = "${realm}?service=${service}&client_id=testclient&scope=${scope}"
    
    $tokenResponse = Invoke-WebRequest -Uri $tokenUri -Method Get -Authentication Basic -Credential $secretCred
    $tokenResponse.Content | ConvertFrom-Json

    Maybe a credential can have additional metadata to indicate that it's an AzAccess token so it does that extra oauth2/exchange step if that's needed for testing but that should definitely not be the default.

  2. jborean93 commented on Feb 22, 2026

    @jborean93
    Author

    I've opened #1949 and created a summary on the changes/risks/reasons behind it all. I'm happy to talk about it further as needed but hopefully this helps explain what is happening and why I made the changes I did.

    Note: This has been generated by AI but I've reviewed/modified the changes as necessary.

    OCI Registry Authentication: Current Issues and Proposed Changes

    Summary

    PSResourceGet's current authentication implementation is tightly coupled to Azure Container Registry (ACR) and doesn't work with other OCI-compliant registries like GitHub Container Registry (GHCR). This document outlines:

    • The Problem: Current implementation only works with ACR and unauthenticated registries (e.g., MCR)
    • Root Causes: ACR-specific authentication workflows, overly broad token scopes, and incompatible HTTP methods
    • The Solution: Implement standard OCI authentication with ACR-specific handling only when needed
    • Breaking Change: Explicit credentials will use standard OCI auth by default; ACR-specific auth requires username prefix
    • Risk: Reliance on service name pattern *.azurecr.io to detect ACR endpoints for automatic Azure login

    Glossary

    Registries

    • OCI (Open Container Initiative) - Open standard that defines container registry APIs
    • ACR (Azure Container Registry) - Azure's OCI registry implementation (e.g., myregistry.azurecr.io)
    • GHCR (GitHub Container Registry) - GitHub's OCI registry implementation (ghcr.io)
    • MAR/MCR (Microsoft Artifact Registry/Microsoft Container Registry) - Public OCI registry for Microsoft artifacts (mcr.microsoft.com)

    Token Types (Authentication Flow)

    Understanding the token types used and their names is critical to understanding the problems:

    1. Azure Access Token - Short-lived token from Azure login (az login, Connect-AzAccount, .NET DefaultAzureCredential)

      • Used with ACR only
      • Not an OCI standard concept
    2. ACR Refresh Token - Short-lived token ACR issues when given an Azure Access Token

      • ACR-specific OAuth2 exchange (/oauth2/exchange)
      • Acts as a password for the next step
    3. Registry Bearer Token - The actual token used for OCI API requests

      • Standard across all OCI registries
      • Has specific scopes defining permissions
    4. Token Scope - Defines what the bearer token can do

      • Format: {resourcetype}:{packagename}:{action}
      • Examples: repository:mymodule:pull, registry:catalog:*
      • Some OCI endpoints support wildcards for sections, others do not

    Current Authentication Workflow

    The current implementation attempts authentication in the following order:

    Step 1: Discover Authentication Requirements

    Send HEAD /v2/ to the registry and check the response:

    • 200 OK → Registry is unauthenticated (e.g., MCR), no bearer token needed
    • 401 Unauthorized → Extract realm and service from WWW-Authenticate header
    • Other → Treated as error

    Example WWW-Authenticate headers:

    # ACR
    (Invoke-WebRequest https://psresourcegettest.azurecr.io/v2/ -SkipHttpErrorCheck).Headers['WWW-Authenticate']
    # Bearer realm="https://psresourcegettest.azurecr.io/oauth2/token",service="psresourcegettest.azurecr.io"
    
    # GHCR
    (Invoke-WebRequest https://ghcr.io/v2/ -SkipHttpErrorCheck).Headers['WWW-Authenticate']
    # Bearer realm="https://ghcr.io/token",service="ghcr.io",scope="repository:user/image:pull"
    
    # MCR - No authentication
    (Invoke-WebRequest https://mcr.microsoft.com/v2/ -SkipHttpErrorCheck).StatusCode
    # 200

    Step 2: Try Anonymous Access

    Request a bearer token anonymously from {realm}?service={service}&scope={scope} with no Authorization header.

    Scope used:

    • repository:*:* for package operations
    • registry:catalog:* for catalog/search operations

    If this succeeds, use the returned bearer token from the access_token key for API requests.

    Step 3: Try Authenticated Access (ACR-Specific)

    If anonymous access fails:

    1. Check for credential from Register-PSResourceRepository OR attempt to get Azure Access Token via DefaultAzureCredential (environment/browser login)
    2. If an Azure Access Token is available, perform ACR-specific OAuth2 exchange:
      • Exchange Azure Access Token → ACR Refresh Token
      • Exchange ACR Refresh Token → Registry Bearer Token
    3. Use the registry bearer token for API requests

    Key Limitation: This workflow assumes all explicit credentials are Azure Access Tokens and always uses the ACR OAuth2 flow.

    Problems with Current Implementation

    The current implementation works for ACR and unauthenticated registries (MCR) but fails with other OCI registries (GHCR, Docker Hub, etc.). Issues fall into three categories:

    1. OCI Spec Compatibility Issues

    Problem: Using HEAD /v2/ instead of GET /v2/

    The OCI spec recommends GET /v2/ for the version check endpoint. Some registries don't support HEAD:

    # GHCR rejects HEAD requests
    Invoke-WebRequest -Method Head -Uri https://ghcr.io/v2/
    # Invoke-WebRequest: Response status code does not indicate success: 405 (Method Not Allowed)
    
    # GET works as expected
    Invoke-WebRequest -Method Get -Uri https://ghcr.io/v2/
    # Returns 401 with WWW-Authenticate header (expected behavior)

    Impact: PSResourceGet fails immediately when trying to use GHCR.

    Problem: Overly Broad Token Scopes

    Current implementation requests wildcard scopes (repository:*:*) which many registries reject:

    # GHCR rejects wildcard scopes
    Invoke-WebRequest -Method Get -Uri 'https://ghcr.io/token?service=ghcr.io&scope=repository:*:*'
    # ERROR: "requested access to the resource is denied"
    
    # GHCR accepts package-specific scopes
    Invoke-WebRequest -Method Get -Uri 'https://ghcr.io/token?service=ghcr.io&scope=repository:jborean93/publishtest:pull'
    # SUCCESS: Returns anonymous bearer token

    Impact: Anonymous and authenticated access fails even for public packages on GHCR.

    Problem: Anonymous token is only checked under access_token

    Current implementation only uses the access_token key in the GET /v2/ response but OCI registries can return it on either token or access_token https://distribution.github.io/distribution/spec/auth/token/#token-response-fields.

    For compatibility with OAuth 2.0, we will also accept token under the name access_token. At least one of these fields must be specified

    (Invoke-WebRequest -Method Get -Uri 'https://ghcr.io/token?service=ghcr.io&scope=repository:jborean93/publishtest:pull').Content
    # {"token":"...."} 
    
    # This has been configured to allow anonymous access
    # I'll be removing this registry once all this has been sorted so
    # this link may not work in the future.
    (Invoke-WebRequest -Method Get -Uri 'https://jboreancrtest.azurecr.io/oauth2/token?service=jboreancrtest.azurecr.io&scope=repository:publishtest:pull').Content
    # {"access_token":"..."}

    2. ACR-Specific Assumptions

    Problem: All Explicit Credentials Use ACR OAuth2 Flow

    The current code assumes any provided credential is an Azure Access Token and always performs the ACR-specific OAuth2 exchange. This makes it impossible to use:

    • Entra Service Principal credentials (client ID + secret) for long-lived ACR authentication
    • Standard username/password credentials for non-ACR registries (GHCR tokens, Docker Hub, etc.)

    Impact: Cannot authenticate using longer lived Entra client secret or to non-ACR registries with credentials.

    Problem: Azure Login Attempted for All Registries

    When no explicit credential is provided, the code attempts to retrieve an Azure Access Token via DefaultAzureCredential (environment variables or browser login) regardless of registry type. This is made worse when there is no credential present and the browser cannot be displayed (VM, SSH logon, etc) as an error will be displayed.

    Impact: Users get unnecessary Azure login prompts when installing from GHCR or other non-ACR registries.

    3. ACR Credential Limitations

    Problem: Cannot Use Service Principals Directly

    ACR supports authentication with Entra Service Principals (client ID + secret), which are suitable for automation and long-lived scenarios. However, the current implementation can only use short-lived Azure Access Tokens.

    Impact: Users cannot create stable, long-lived credentials for ACR in automation scenarios.

    Proposed Changes

    This PR implements standard OCI authentication with ACR-specific handling only when needed. Here's how each change addresses the problems:

    1. Fix OCI Compatibility Issues

    Change Addresses Details
    Use GET /v2/ instead of HEAD /v2/ Method Not Allowed on GHCR Follows OCI spec recommendation
    Use package-specific scopes Wildcard rejection on GHCR repository:{packagename}:pull for install
    repository:{packagename}:push,pull for publish
    registry:catalog:* only for catalog operations
    Simplify anonymous token requests Unnecessary complexity Use query parameters only (no form body needed)
    Use token or access_token response Different return JSON structures Some OCI registries return token or access_token in the bearer token response exchange

    2. Implement Standard OCI Authentication

    New Authentication Flow:

    1. Discover authentication requirements - GET /v2/ (changed from HEAD)
    2. Try anonymous access with package-specific scope (changed from wildcard)
    3. If credentials provided (new: -Credential parameter support on Install-PSResource/Publish-PSResource):
      • Default: Use standard OCI basic auth (username/password → bearer token)
      • ACR special case: If username in the format AzureAccessToken: GUID, use ACR OAuth2 flow
      • Currently this credential is set as HttpClientHandler.Credential which should work but
      • The various issues above means it's never really used and for ACR it only works for a clientId:clientSecret combo (no access token)
    4. If no credentials and registry service ends with .azurecr.io:
      • Try DefaultAzureCredential (environment/browser login)
      • Use ACR OAuth2 flow with the Azure Access Token

    3. Key Behavioral Changes

    Now Supported:

    • GHCR, Docker Hub, and other OCI registries
    • Entra Service Principal credentials for ACR (client ID + secret)
    • Standard username/password for any OCI registry
    • Per-operation credentials via -Credential parameter

    Breaking Change:

    • Explicit credentials use standard OCI auth by default breaking a credential with a short lived Azure Access Token
    • ACR-specific OAuth2 flow now requires username prefix: AzureAccessToken: GUID

    ACR Auto-Login:

    • Only triggered when service from WWW-Authenticate ends with .azurecr.io
    • Prevents unwanted Azure login prompts for non-ACR registries

    Breaking Changes

    Change: Credential Handling for ACR

    Before (PSResourceGet 1.1.1+):

    # Any credential automatically used ACR OAuth2 flow
    Register-PSResourceRepository -Name MyACR -Uri https://myregistry.azurecr.io -CredentialInfo $cred
    # $cred assumed to be tenantId:Azure Access Token, always uses ACR OAuth2

    After (This PR):

    # Standard credentials use OCI Basic token exchange
    Set-Secret -Name 'clientId' -Value (ConvertTo-SecureString 'client-secret' -AsPlainText)
    
    $cred = [PSCredentialInfo]@{
        VaultName = "SecretStore"
        SecretName = 'clientId'
    }
    Register-PSResourceRepository -Name MyACR -Uri https://myregistry.azurecr.io -CredentialInfo $cred
    
    # Azure Access Tokens need explicit prefix
    $azt = Get-AzureAccessToken
    
    Set-Secret -Name "AzureAccessToken: $tenantId" -Secret $azt.Token -Verbose
    $cred = [PSCredentialInfo]@{
        VaultName = "SecretStore"
        SecretName = "AzureAccessToken: $tenantId"
    }
    Register-PSResourceRepository -Name MyACR -Uri https://myregistry.azurecr.io -CredentialInfo $cred

    Impact Assessment

    Who is affected:

    • Users storing credentials with Register-PSResourceRepository for ACR

    Likelihood of impact:

    • Low - This behavior was never documented and only existed since v1.1.1
    • Azure Access Tokens are short-lived (hours), so storing them in repository registration doesn't make practical sense
    • Most users likely rely on DefaultAzureCredential (auto-login) rather than explicit tokens

    Migration path:

    • If you were storing Azure Access Tokens: Add AzureAccessToken: GUID username prefix where GUID is the tenantId, or
    • Use Service Principal credentials (client ID + secret) for automation scenarios

    Why This Change is Beneficial

    1. Enables Service Principal support - Long-lived credentials for automation (previously impossible)
    2. Enables non-ACR registries - GHCR, Docker Hub, etc. can now use credentials
    3. Follows OCI standards - Default behavior matches standard OCI authentication
    4. Still supports Azure tokens - Just requires explicit opt-in via username prefix

    Potential Risks and Concerns

    Primary Risk: ACR Detection via Service Name Pattern

    The Issue:

    The PR uses the service value from the WWW-Authenticate header to detect ACR registries:

    # ACR returns service ending with .azurecr.io
    Bearer realm="https://myregistry.azurecr.io/oauth2/token",service="myregistry.azurecr.io"

    Code checks: if ($service -like "*.azurecr.io") → trigger Azure auto-login

    Why This Matters:

    This pattern-matching is critical because we cannot trigger DefaultAzureCredential (browser login prompts) for non-ACR registries. The code must distinguish between ACR and other OCI registries.

    The Risk:

    If Azure changes the service value format in the future (unlikely but possible), the detection would break and:

    • ACR auto-login would stop working
    • Users would need to provide explicit credentials

    Likelihood: Low - Service names are typically tied to DNS and ACR architecture

    Mitigation: The behavior degrades gracefully - explicit credentials still work

    Alternative Approaches Considered

    Option 1: Explicit ACR Flag (More Conservative)

    Add a switch to Register-PSResourceRepository to explicitly mark ACR registries:

    Register-PSResourceRepository -Name MyACR -Uri https://myregistry.azurecr.io -IsAzureContainerRegistry

    Pros:

    • No reliance on service name pattern
    • Explicit user intent
    • Future-proof against Azure changes

    Cons:

    • Extra parameter users must know about
    • Breaking change for ACR auto-login (requires re-registration)
    • More complex UX

    Option 2: New ApiVersion for OCI Standards

    Add -ApiVersion OciRegistry while keeping ContainerRegistry for legacy ACR behavior:

    # Legacy ACR-only behavior (default, backwards compatible)
    Register-PSResourceRepository -Name MyACR -Uri ... -ApiVersion ContainerRegistry
    
    # New OCI-standard behavior
    Register-PSResourceRepository -Name MyGHCR -Uri ... -ApiVersion OciRegistry

    Pros:

    • Full backwards compatibility
    • Clear distinction between legacy and standard behavior

    Cons:

    • Maintains technical debt
    • Users must know which ApiVersion to use
    • ACR users wouldn't benefit from improvements without migration

    Option 3: Metadata-Based Credential Typing

    Use SecretManagement metadata to indicate credential type:

    Set-Secret -Name ACRToken -Secret $cred -Metadata @{ Type = "AzureAccessToken" }

    Pros:

    • No username prefix needed
    • Explicit credential type

    Cons:

    • Requires SecretManagement module
    • More complex credential management
    • Doesn't solve the broader OCI compatibility issues
    • Doesn't solve the implicit Azure env/browser lookup problem

    Recommended Approach (Current PR)

    Why the pattern-matching approach is best:

    1. Minimal breaking change - Only affects undocumented behavior since v1.1.1
    2. Best user experience - ACR auto-login continues to "just work"
    3. Enables new scenarios - GHCR, Service Principals, etc.
    4. Graceful degradation - If detection fails, explicit credentials still work
    5. Follows standards - Default behavior matches OCI spec

    The service name pattern is stable (tied to Azure's DNS infrastructure) and the risk is acceptable given the benefits.

    Summary

    This PR transforms PSResourceGet from an ACR-centric implementation to a proper OCI-compliant registry client while maintaining ACR-specific features where needed.

    What works now that didn't before:

    • GitHub Container Registry (GHCR)
    • Docker Hub and other OCI registries
    • Entra Service Principal credentials for ACR automation
    • Per-operation credentials via -Credential parameter
    • Package-specific token scopes (security best practice)

    What continues to work:

    • ACR with Azure auto-login (environment/browser)
    • ACR with explicit Azure Access Tokens (requires username prefix)
    • Unauthenticated registries (MCR)

    The tradeoff:

    • Breaking change for undocumented Azure Access Token storage (fixable with username prefix)
    • Relies on service name pattern to detect ACR (low risk, graceful degradation)
  3. SydneyhSmith commented on Aug 13, 2026

    @SydneyhSmith
    Collaborator

    We are working on getting the ORAS .net library merged in which hopefully should resolve some of these issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions