PluginProbe
HubSpot All-In-One Marketing – Forms, Popups, Live Chat / 11.3.61
HubSpot All-In-One Marketing – Forms, Popups, Live Chat v11.3.61
11.3.75 11.3.73 11.3.71 11.3.70 11.3.69 11.3.64 11.3.65 11.3.62 11.3.61 11.3.56 11.3.58 11.0.31 11.0.52 11.0.54 11.0.56 11.0.58 11.0.7 11.1.10 11.1.11 11.1.13 11.1.14 11.1.15 11.1.2 11.1.20 11.1.21 All 73 releases
leadin / public / modules / api / class-access-token-api-controller.php

class-access-token-api-controller.php in HubSpot All-In-One Marketing – Forms, Popups, Live Chat 11.3.61, at public/modules/api/class-access-token-api-controller.php

122 lines 3.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Leadin\api;
4
5 use Leadin\api\Base_Api_Controller;
6 use Leadin\auth\OAuth;
7 use Leadin\auth\OAuthCrypto;
8 use Leadin\data\Filters;
9 use Leadin\data\Portal_Options;
10
11 class Access_Token_Api_Controller extends Base_Api_Controller {
12
13 const CACHE_KEY = 'leadin_access_token';
14
15 public function __construct() {
16 // Uses register_leadin_route → edit_posts capability
17 // Safe because only short-lived access token is returned,
18 // NOT the long-lived refresh token
19 self::register_leadin_route(
20 '/access-token',
21 \WP_REST_Server::READABLE,
22 array( $this, 'get_access_token' )
23 );
24 }
25
26 public function get_access_token() {
27 $cached = get_transient( self::CACHE_KEY );
28 if ( ! empty( $cached ) ) {
29 $cached_data = json_decode( $cached, true );
30 if ( ! empty( $cached_data['accessToken'] )
31 && ! empty( $cached_data['expiresAt'] )
32 && $cached_data['expiresAt'] > ( time() + 300 ) ) {
33 return new \WP_REST_Response(
34 array(
35 'accessToken' => $cached_data['accessToken'],
36 'expiresIn' => $cached_data['expiresAt'] - time(),
37 ),
38 200
39 );
40 }
41 }
42
43 $refresh_token = OAuth::get_refresh_token();
44
45 if ( false === $refresh_token ) {
46 return new \WP_REST_Response(
47 array( 'error' => 'decrypt_failed' ),
48 500
49 );
50 }
51
52 if ( empty( $refresh_token ) ) {
53 return new \WP_REST_Response(
54 array( 'error' => 'not_connected' ),
55 403
56 );
57 }
58
59 // Server-side exchange — refresh token never leaves PHP.
60 // The /wordpress/v1/oauth/refresh endpoint takes the token as a query
61 // parameter (consistent with the existing browser-side JS client contract).
62 $api_url = Filters::apply_base_api_url_filters() . '/wordpress/v1/oauth/refresh';
63 $response = wp_remote_post(
64 $api_url . '?refresh_token=' . rawurlencode( $refresh_token ),
65 array( 'timeout' => 15 )
66 );
67
68 if ( is_wp_error( $response ) ) {
69 return new \WP_REST_Response(
70 array( 'error' => 'refresh_failed' ),
71 500
72 );
73 }
74
75 $response_code = wp_remote_retrieve_response_code( $response );
76 if ( 200 !== $response_code ) {
77 return new \WP_REST_Response(
78 array(
79 'error' => 'refresh_failed',
80 'code' => $response_code,
81 ),
82 500
83 );
84 }
85
86 $body = json_decode( wp_remote_retrieve_body( $response ), true );
87
88 if ( empty( $body ) || empty( $body['access_token'] ) ) {
89 return new \WP_REST_Response(
90 array( 'error' => 'invalid_response' ),
91 500
92 );
93 }
94
95 $expires_in = isset( $body['expires_in'] ) ? (int) $body['expires_in'] : 0;
96
97 if ( ! empty( $body['refresh_token'] ) ) {
98 $encrypted_new_token = OAuthCrypto::encrypt( $body['refresh_token'] );
99 Portal_Options::set_refresh_token( $encrypted_new_token );
100 }
101
102 if ( $expires_in > 300 ) {
103 $cache_data = json_encode(
104 array(
105 'accessToken' => $body['access_token'],
106 'expiresAt' => time() + $expires_in,
107 )
108 );
109 set_transient( self::CACHE_KEY, $cache_data, $expires_in - 300 );
110 }
111
112 // Return ONLY the access token — refresh token stays server-side
113 return new \WP_REST_Response(
114 array(
115 'accessToken' => $body['access_token'],
116 'expiresIn' => $expires_in,
117 ),
118 200
119 );
120 }
121 }
122