Home > database >  OpenIddict support returning authorization code via GET request for postman
OpenIddict support returning authorization code via GET request for postman

Time:12-08

I have set up an Authorization Server using OpenIddict 3.1.1 (porting over an existing one that was using the older ASOS package directly). I believe I am most of the way there, because when using the client application, I am able to log in, give consent, redirect back to the client, and exchange the authorization code for an access token.

However, when I try to do the same using Postman's OAuth 2.0 authentication support, I am able to log in (and give consent), but when it completes and returns the authorization code, I receive an HTTP 403 from the https://oauth.pstmn.io/v1/callback that I am redirected to:

403 ERROR
The request could not be satisfied.
This distribution is not configured to allow the HTTP request method that was used for this request. The distribution supports only cachable requests. We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
Generated by cloudfront (CloudFront)
Request ID: UAXpago6ISiqbgm9U_SVPwh96qz1qoveZWFd0Cra-2FximeWZiY2aQ==

From what I can tell, this is because OpenIddict is issuing a POST request back to the callback url. This works for my client application, but evidently is not supported by Postman.

What configuration tweak do I need to make to OpenIddict to support this in postman?

OpenIddict related config in Startup.ConfigureServices:

services.AddOpenIddict()
        .AddCore(options => { 
            options.AddApplicationStore<ClientStore>();
            options.UseEntityFramework()
                .UseDbContext<OAuthServerDbContext>()
                .ReplaceDefaultEntities<Client, Authorization, OAuthScope, Token, long>()
        ;
        })
        .AddServer(options => {
            options.RegisterClaims();

            options.RegisterScopes(OpenIddictConstants.Scopes.OpenId,
                OpenIddictConstants.Scopes.Email,
                OpenIddictConstants.Scopes.OfflineAccess,
                OpenIddictConstants.Scopes.Profile,
                "user");

            // flows
            options.AllowAuthorizationCodeFlow();
            options.AllowRefreshTokenFlow();
            options.AllowPasswordFlow();
            options.AllowHybridFlow();
            // implicit is used by postman
            options.AllowImplicitFlow();

            var serviceProvider = options.Services.BuildServiceProvider();
            var oauthConstants = serviceProvider.GetRequiredService<IOptions<OAuthConstants>>().Value;
            var tokenLifetimes = serviceProvider
                .GetRequiredService<IOptions<OpenIdConnectServerTokenLifetimeSettings>>().Value;

            // security
            options.SetAccessTokenLifetime(tokenLifetimes.AccessTokenLifetime)
                .SetAuthorizationCodeLifetime(tokenLifetimes.AuthorizationCodeLifetime)
                .SetIdentityTokenLifetime(tokenLifetimes.IdentityTokenLifetime)
                .SetRefreshTokenLifetime(tokenLifetimes.RefreshTokenLifetime);

            options.SetIssuer(new Uri("https://localhost/oauth/"));

            // custom handlers added here
            options.AddEventHandlers();

            // certificate details hidden
            options.AddEncryptionCertificate(certificate);


            // endpoints
            options.SetAuthorizationEndpointUris("/OpenIdConnect/Authorize");
            options.SetLogoutEndpointUris("/OpenIdConnect/Logout", "/Account/Logout");

            options.SetRevocationEndpointUris("/OpenIdConnect/Revoke");
            options.SetTokenEndpointUris("/OpenIdConnect/Token");

            options.SetCryptographyEndpointUris("/OpenIdConnect/JWKDoc");
            options.SetUserinfoEndpointUris("/OpenIdConnect/UserInfo");

            options.UseAspNetCore()
                .EnableStatusCodePagesIntegration()
                .EnableAuthorizationEndpointPassthrough()
                //.EnableTokenEndpointPassthrough()
                .EnableLogoutEndpointPassthrough()
                .EnableUserinfoEndpointPassthrough()
                ;
        })
        .AddValidation(options => {
             options.UseLocalServer();

            options.UseAspNetCore();

            var serviceProvider = options.Services.BuildServiceProvider();

            var config = serviceProvider.GetRequiredService<IConfiguration>();
            options.SetClientId(config.GetValue<string>(nameof(Settings.OAuthClientId)));
            options.SetClientSecret(config.GetValue<string>(nameof(Settings.ClientSecret)));

            // certificate details hidden
            options.AddEncryptionCertificate(certificate);
        });

Postman details:

Authorization
Token Name: Redacted
Grant Type: Authorization Code
Callback URL: disabled, https://oauth.pstmn.io/v1/callback
Authorize using browser: checked
Auth URL: https://localhost/oauth/OpenIdConnect/Authorize
Access Token URL: https://localhost/oauth/OpenIdConnect/Token
Client ID: redacted, but correct
Client Secret: redacted, but correct
Scope: openid offline_access
State:
Client Authentication: Send client credentials in body

edit: The response that it sends to the postman callback URI does include the authorization code in the body, but because of the 403 response, Postman doesn't parse that out and make the follow-up request to exchange the code for the token.

CodePudding user response:

There is an option that you can set to control if the authorization code is received in the URL as a query string or in the body as a post. The option is response_mode and you control that as a client.

I believe if it is not set to response_mode=form_post, then you will get the code in the URL instead.

See the details about this parameter here.

  • Related