Class: WalmartApIs::AuthorizationApi

Inherits:
BaseApi
  • Object
show all
Defined in:
lib/walmart_ap_is/apis/authorization_api.rb

Overview

AuthorizationApi

Constant Summary

Constants inherited from BaseApi

BaseApi::GLOBAL_ERRORS

Instance Attribute Summary

Attributes inherited from BaseApi

#config, #http_call_back

Instance Method Summary collapse

Methods inherited from BaseApi

#initialize, #new_parameter, #new_request_builder, #new_response_handler, user_agent, user_agent_parameters

Constructor Details

This class inherits a constructor from WalmartApIs::BaseApi

Instance Method Details

#authorize(response_type, client_id, redirect_uri, scope, state, code_challenge, code_challenge_method) ⇒ ApiResponse

Browser endpoint for the authorization-code grant (RFC 6749 §3.1). The Solution Provider redirects the seller here; the seller authenticates and consents at Walmart IAM, and the response redirects to redirect_uri with a single-use code.

  • PKCE requiredcode_challenge + code_challenge_method=S256 (RFC 7636). plain is not accepted.
  • Exact redirect_uri match against a value registered for the client.
  • state required; echoed back verbatim (CSRF).
  • The success and error redirects (performed by IAM) carry iss (RFC 9207); clients MUST validate it. Error handling. For a valid request, this endpoint 302-redirects to the Walmart IAM consent URL; IAM then drives consent and performs the RFC 6749 §4.1.2.1 redirect back to the client's redirect_uri (success or error), because IAM is the party that can verify the redirect_uri is registered. For request-level errors that authorization-service itself detects (missing/invalid client_id/redirect_uri, response_type != code, code_challenge_method != S256), it returns a JSON 400 (AuthorizeError). It deliberately does not redirect these errors to the supplied redirect_uri: the proxy has no client registry, so self-redirecting to an unverified URI would be an open redirect.

Upstream status (ADR-048, pending): iss emission, exact-redirect enforcement, and server-side rejection of code_challenge_method=plain are IAM / app-store responsibilities not yet fully in place. authorization-service enforces the request-side invariants it can and redirects valid requests to IAM; the full guarantee lands when those upstream changes ship. identifier. exactly match a registered value. offline_access to receive a refresh token. unchanged. base64url(SHA-256(code_verifier)). Must be S256.

Parameters:

  • response_type (ResponseType1)

    Required parameter: Must be code.

  • client_id (String)

    Required parameter: The registered client

  • redirect_uri (String)

    Required parameter: Callback URI; must

  • scope (String)

    Required parameter: Space-delimited scopes. Include

  • state (String)

    Required parameter: Opaque CSRF token; echoed back

  • code_challenge (String)

    Required parameter: PKCE challenge —

  • code_challenge_method (CodeChallengeMethod)

    Required parameter:

Returns:

  • (ApiResponse)

    Complete http response with raw body and status code.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/walmart_ap_is/apis/authorization_api.rb', line 157

def authorize(response_type,
              client_id,
              redirect_uri,
              scope,
              state,
              code_challenge,
              code_challenge_method)
  @api_call
    .request(new_request_builder(HttpMethodEnum::GET,
                                 '/auth/v4/authorize',
                                 Server::DEFAULT)
               .query_param(new_parameter(response_type, key: 'response_type')
                             .is_required(true))
               .query_param(new_parameter(client_id, key: 'client_id')
                             .is_required(true))
               .query_param(new_parameter(redirect_uri, key: 'redirect_uri')
                             .is_required(true))
               .query_param(new_parameter(scope, key: 'scope')
                             .is_required(true))
               .query_param(new_parameter(state, key: 'state')
                             .is_required(true))
               .query_param(new_parameter(code_challenge, key: 'code_challenge')
                             .is_required(true))
               .query_param(new_parameter(code_challenge_method, key: 'code_challenge_method')
                             .is_required(true)))
    .response(new_response_handler
                .is_response_void(true)
                .is_api_response(true)
                .local_error('400',
                             'Non-redirectable request (bad `client_id`/`redirect_uri`).',
                             AuthorizeErrorException)
                .local_error('429',
                             'Rate limit exceeded.',
                             OauthErrorException)
                .local_error('500',
                             'Internal error.',
                             OauthErrorException))
    .execute
end

#create_token(grant_type, client_id: nil, client_secret: nil, code: nil, code_verifier: nil, refresh_token: nil, redirect_uri: nil, scope: nil) ⇒ ApiResponse

Exchanges a grant for an OAuth access token. Supported grant_type values: | grant_type | Flow | Required (besides grant_type) | |----------------------|------------------|------------------------------- --| | client_credentials | seller-direct | client auth (see below) | | authorization_code | delegated | code, code_verifier (PKCE) | | refresh_token | delegated | refresh_token | Client authentication: credentials in the form body (client_secret_post) — client_id + client_secret. HTTP Basic is also accepted. Public clients (Solution-Provider apps registered token_endpoint_auth_method: none) send no secret on the delegated grants; PKCE protects the code. client_credentials: issues no refresh token (re-mint on expiry). scope is decorative here — accepted for compatibility but not honored; access is governed by the scopes provisioned per client in IAM (ADR-012); there is no down-scoping and the response does not echo scope. (Verified: /v3/token ignores any scope= value.) authorization_code: redirect_uri is accepted for OAuth 2.0 back-compat but not required in 2.1 (PKCE covers injection). refresh_token: the response includes a rotated refresh_token — the presented token is invalidated (OAuth 2.1 §4.3.1; IAM rotates today, ~1-year TTL). A requested scope MUST NOT exceed the originally granted scope. Token: Bearer (RFC 6750), sent downstream as Authorization: Bearer <token>not WM_SEC.ACCESS_TOKEN. Implemented by authorization-service as a stateless proxy to Walmart IAM (ADR-026). (client_secret_post / public clients). Omit if using HTTP Basic. (client_secret_post). Omit for public clients or HTTP Basic. /auth/v4/authorize (authorization_code grant). hash equals the earlier code_challenge (authorization_code grant). refresh token (refresh_token grant). Rotated on use. back-compat on authorization_code; not required in 2.1 (PKCE covers injection). for compatibility but not honored (ADR-012) — no down-scoping; not echoed. refresh_token: optional; MUST NOT exceed the originally granted scope.

Parameters:

  • grant_type (GrantType)

    Required parameter: The OAuth grant type.

  • client_id (String) (defaults to: nil)

    Optional parameter: Client identifier

  • client_secret (String) (defaults to: nil)

    Optional parameter: Client secret

  • code (String) (defaults to: nil)

    Optional parameter: Authorization code from

  • code_verifier (String) (defaults to: nil)

    Optional parameter: PKCE verifier whose S256

  • refresh_token (String) (defaults to: nil)

    Optional parameter: A previously issued

  • redirect_uri (String) (defaults to: nil)

    Optional parameter: Accepted for OAuth 2.0

  • scope (String) (defaults to: nil)

    Optional parameter: client_credentials: accepted

Returns:

  • (ApiResponse)

    Complete http response with raw body and status code.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/walmart_ap_is/apis/authorization_api.rb', line 66

def create_token(grant_type,
                 client_id: nil,
                 client_secret: nil,
                 code: nil,
                 code_verifier: nil,
                 refresh_token: nil,
                 redirect_uri: nil,
                 scope: nil)
  @api_call
    .request(new_request_builder(HttpMethodEnum::POST,
                                 '/auth/v4/token',
                                 Server::DEFAULT)
               .form_param(new_parameter(grant_type, key: 'grant_type')
                            .is_required(true))
               .form_param(new_parameter(client_id, key: 'client_id'))
               .form_param(new_parameter(client_secret, key: 'client_secret'))
               .form_param(new_parameter(code, key: 'code'))
               .form_param(new_parameter(code_verifier, key: 'code_verifier'))
               .form_param(new_parameter(refresh_token, key: 'refresh_token'))
               .form_param(new_parameter(redirect_uri, key: 'redirect_uri'))
               .form_param(new_parameter(scope, key: 'scope'))
               .header_param(new_parameter('application/x-www-form-urlencoded', key: 'content-type'))
               .header_param(new_parameter('application/json', key: 'accept'))
               .auth(Or.new('basicClientAuth')))
    .response(new_response_handler
                .deserializer(APIHelper.method(:custom_type_deserializer))
                .deserialize_into(TokenResponse.method(:from_hash))
                .is_api_response(true)
                .local_error('400',
                             'Invalid token request (RFC 6749 §5.2).',
                             OauthErrorException)
                .local_error('401',
                             'Client authentication failed — `invalid_client`.',
                             OauthErrorException)
                .local_error('429',
                             'Rate limit exceeded.',
                             OauthErrorException)
                .local_error('500',
                             'Internal error.',
                             OauthErrorException))
    .execute
end

#register_client(body) ⇒ ApiResponse

Registers a Solution Provider client and returns its client_id (RFC 7591). Lets Solution Providers onboard without manual registration. Public clients set token_endpoint_auth_method: none (no secret; PKCE required). Confidential clients receive a client_secret. redirect_uris are validated and later enforced by exact match at /auth/v4/authorize. Proxied to Walmart IAM's registration endpoint (ADR-026/ADR-048). RFC 7592 registration management (read/update/delete via a registration_access_token) is not offered in this version. description here

Parameters:

Returns:

  • (ApiResponse)

    Complete http response with raw body and status code.



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'lib/walmart_ap_is/apis/authorization_api.rb', line 208

def register_client(body)
  @api_call
    .request(new_request_builder(HttpMethodEnum::POST,
                                 '/auth/v4/register',
                                 Server::DEFAULT)
               .header_param(new_parameter('application/json', key: 'Content-Type'))
               .body_param(new_parameter(body)
                            .is_required(true))
               .header_param(new_parameter('application/json', key: 'accept'))
               .body_serializer(proc do |param| param.to_json unless param.nil? end))
    .response(new_response_handler
                .deserializer(APIHelper.method(:custom_type_deserializer))
                .deserialize_into(ClientRegistrationResponse.method(:from_hash))
                .is_api_response(true)
                .local_error('400',
                             'Invalid client metadata (RFC 7591 §3.2.2).',
                             RegistrationErrorException)
                .local_error('401',
                             'Registration requires an initial access token and none/invalid'\
                              ' was supplied.',
                             RegistrationErrorException)
                .local_error('429',
                             'Rate limit exceeded.',
                             OauthErrorException)
                .local_error('500',
                             'Internal error.',
                             OauthErrorException))
    .execute
end