Skip to content

Commit 82357ea

Browse files
committed
feat(api): add method to create access token (#249)
1 parent 1ca1e2e commit 82357ea

File tree

9 files changed

+278
-1
lines changed

9 files changed

+278
-1
lines changed

.stats.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
configured_endpoints: 23
1+
configured_endpoints: 24

api.md

+13
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ Methods:
1010

1111
- <code>client.<a href="./src/finch/_client.py">get_access_token</a>(\*args) -> str</code>
1212
- <code>client.<a href="./src/finch/_client.py">get_auth_url</a>(\*args) -> str</code>
13+
- <code>client.<a href="./src/finch/_client.py">with_access_token</a>(\*args) -> Self</code>
14+
15+
# AccessTokens
16+
17+
Types:
18+
19+
```python
20+
from finch.types import CreateAccessTokenResponse
21+
```
22+
23+
Methods:
24+
25+
- <code title="post /auth/token">client.access_tokens.<a href="./src/finch/resources/access_tokens.py">create</a>(\*\*<a href="src/finch/types/access_token_create_params.py">params</a>) -> <a href="./src/finch/types/create_access_token_response.py">CreateAccessTokenResponse</a></code>
1326

1427
# HRIS
1528

src/finch/_client.py

+26
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151

5252

5353
class Finch(SyncAPIClient):
54+
access_tokens: resources.AccessTokens
5455
hris: resources.HRIS
5556
providers: resources.Providers
5657
account: resources.Account
@@ -135,6 +136,7 @@ def __init__(
135136
_strict_response_validation=_strict_response_validation,
136137
)
137138

139+
self.access_tokens = resources.AccessTokens(self)
138140
self.hris = resources.HRIS(self)
139141
self.providers = resources.Providers(self)
140142
self.account = resources.Account(self)
@@ -311,6 +313,16 @@ def get_auth_url(
311313
)
312314
)
313315

316+
def with_access_token(
317+
self,
318+
access_token: str,
319+
) -> Self:
320+
"""
321+
Returns a copy of the current Finch client with the given access token for
322+
authentication.
323+
"""
324+
return self.with_options(access_token=access_token)
325+
314326
@override
315327
def _make_status_error(
316328
self,
@@ -346,6 +358,7 @@ def _make_status_error(
346358

347359

348360
class AsyncFinch(AsyncAPIClient):
361+
access_tokens: resources.AsyncAccessTokens
349362
hris: resources.AsyncHRIS
350363
providers: resources.AsyncProviders
351364
account: resources.AsyncAccount
@@ -430,6 +443,7 @@ def __init__(
430443
_strict_response_validation=_strict_response_validation,
431444
)
432445

446+
self.access_tokens = resources.AsyncAccessTokens(self)
433447
self.hris = resources.AsyncHRIS(self)
434448
self.providers = resources.AsyncProviders(self)
435449
self.account = resources.AsyncAccount(self)
@@ -606,6 +620,16 @@ def get_auth_url(
606620
)
607621
)
608622

623+
def with_access_token(
624+
self,
625+
access_token: str,
626+
) -> Self:
627+
"""
628+
Returns a copy of the current Finch client with the given access token for
629+
authentication.
630+
"""
631+
return self.with_options(access_token=access_token)
632+
609633
@override
610634
def _make_status_error(
611635
self,
@@ -642,6 +666,7 @@ def _make_status_error(
642666

643667
class FinchWithRawResponse:
644668
def __init__(self, client: Finch) -> None:
669+
self.access_tokens = resources.AccessTokensWithRawResponse(client.access_tokens)
645670
self.hris = resources.HRISWithRawResponse(client.hris)
646671
self.providers = resources.ProvidersWithRawResponse(client.providers)
647672
self.account = resources.AccountWithRawResponse(client.account)
@@ -651,6 +676,7 @@ def __init__(self, client: Finch) -> None:
651676

652677
class AsyncFinchWithRawResponse:
653678
def __init__(self, client: AsyncFinch) -> None:
679+
self.access_tokens = resources.AsyncAccessTokensWithRawResponse(client.access_tokens)
654680
self.hris = resources.AsyncHRISWithRawResponse(client.hris)
655681
self.providers = resources.AsyncProvidersWithRawResponse(client.providers)
656682
self.account = resources.AsyncAccountWithRawResponse(client.account)

src/finch/resources/__init__.py

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
from .account import Account, AsyncAccount, AccountWithRawResponse, AsyncAccountWithRawResponse
66
from .webhooks import Webhooks, AsyncWebhooks
77
from .providers import Providers, AsyncProviders, ProvidersWithRawResponse, AsyncProvidersWithRawResponse
8+
from .access_tokens import (
9+
AccessTokens,
10+
AsyncAccessTokens,
11+
AccessTokensWithRawResponse,
12+
AsyncAccessTokensWithRawResponse,
13+
)
814
from .request_forwarding import (
915
RequestForwarding,
1016
AsyncRequestForwarding,
@@ -13,6 +19,10 @@
1319
)
1420

1521
__all__ = [
22+
"AccessTokens",
23+
"AsyncAccessTokens",
24+
"AccessTokensWithRawResponse",
25+
"AsyncAccessTokensWithRawResponse",
1626
"HRIS",
1727
"AsyncHRIS",
1828
"HRISWithRawResponse",

src/finch/resources/access_tokens.py

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# File generated from our OpenAPI spec by Stainless.
2+
3+
from __future__ import annotations
4+
5+
import httpx
6+
7+
from ..types import CreateAccessTokenResponse, access_token_create_params
8+
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
9+
from .._utils import maybe_transform
10+
from .._compat import cached_property
11+
from .._resource import SyncAPIResource, AsyncAPIResource
12+
from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper
13+
from .._base_client import (
14+
make_request_options,
15+
)
16+
17+
__all__ = ["AccessTokens", "AsyncAccessTokens"]
18+
19+
20+
class AccessTokens(SyncAPIResource):
21+
@cached_property
22+
def with_raw_response(self) -> AccessTokensWithRawResponse:
23+
return AccessTokensWithRawResponse(self)
24+
25+
def create(
26+
self,
27+
*,
28+
client_id: str,
29+
client_secret: str,
30+
code: str,
31+
redirect_uri: str,
32+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
33+
# The extra values given here take precedence over values defined on the client or passed to this method.
34+
extra_headers: Headers | None = None,
35+
extra_query: Query | None = None,
36+
extra_body: Body | None = None,
37+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
38+
) -> CreateAccessTokenResponse:
39+
"""
40+
Exchange the authorization code for an access token
41+
42+
Args:
43+
extra_headers: Send extra headers
44+
45+
extra_query: Add additional query parameters to the request
46+
47+
extra_body: Add additional JSON properties to the request
48+
49+
timeout: Override the client-level default timeout for this request, in seconds
50+
"""
51+
return self._post(
52+
"/auth/token",
53+
body=maybe_transform(
54+
{
55+
"client_id": client_id,
56+
"client_secret": client_secret,
57+
"code": code,
58+
"redirect_uri": redirect_uri,
59+
},
60+
access_token_create_params.AccessTokenCreateParams,
61+
),
62+
options=make_request_options(
63+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
64+
),
65+
cast_to=CreateAccessTokenResponse,
66+
)
67+
68+
69+
class AsyncAccessTokens(AsyncAPIResource):
70+
@cached_property
71+
def with_raw_response(self) -> AsyncAccessTokensWithRawResponse:
72+
return AsyncAccessTokensWithRawResponse(self)
73+
74+
async def create(
75+
self,
76+
*,
77+
client_id: str,
78+
client_secret: str,
79+
code: str,
80+
redirect_uri: str,
81+
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
82+
# The extra values given here take precedence over values defined on the client or passed to this method.
83+
extra_headers: Headers | None = None,
84+
extra_query: Query | None = None,
85+
extra_body: Body | None = None,
86+
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
87+
) -> CreateAccessTokenResponse:
88+
"""
89+
Exchange the authorization code for an access token
90+
91+
Args:
92+
extra_headers: Send extra headers
93+
94+
extra_query: Add additional query parameters to the request
95+
96+
extra_body: Add additional JSON properties to the request
97+
98+
timeout: Override the client-level default timeout for this request, in seconds
99+
"""
100+
return await self._post(
101+
"/auth/token",
102+
body=maybe_transform(
103+
{
104+
"client_id": client_id,
105+
"client_secret": client_secret,
106+
"code": code,
107+
"redirect_uri": redirect_uri,
108+
},
109+
access_token_create_params.AccessTokenCreateParams,
110+
),
111+
options=make_request_options(
112+
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
113+
),
114+
cast_to=CreateAccessTokenResponse,
115+
)
116+
117+
118+
class AccessTokensWithRawResponse:
119+
def __init__(self, access_tokens: AccessTokens) -> None:
120+
self.create = to_raw_response_wrapper(
121+
access_tokens.create,
122+
)
123+
124+
125+
class AsyncAccessTokensWithRawResponse:
126+
def __init__(self, access_tokens: AsyncAccessTokens) -> None:
127+
self.create = async_to_raw_response_wrapper(
128+
access_tokens.create,
129+
)

src/finch/types/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,7 @@
1313
from .provider import Provider as Provider
1414
from .introspection import Introspection as Introspection
1515
from .disconnect_response import DisconnectResponse as DisconnectResponse
16+
from .access_token_create_params import AccessTokenCreateParams as AccessTokenCreateParams
17+
from .create_access_token_response import CreateAccessTokenResponse as CreateAccessTokenResponse
1618
from .request_forwarding_forward_params import RequestForwardingForwardParams as RequestForwardingForwardParams
1719
from .request_forwarding_forward_response import RequestForwardingForwardResponse as RequestForwardingForwardResponse
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# File generated from our OpenAPI spec by Stainless.
2+
3+
from __future__ import annotations
4+
5+
from typing_extensions import Required, TypedDict
6+
7+
__all__ = ["AccessTokenCreateParams"]
8+
9+
10+
class AccessTokenCreateParams(TypedDict, total=False):
11+
client_id: Required[str]
12+
13+
client_secret: Required[str]
14+
15+
code: Required[str]
16+
17+
redirect_uri: Required[str]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# File generated from our OpenAPI spec by Stainless.
2+
3+
from .._models import BaseModel
4+
5+
__all__ = ["CreateAccessTokenResponse"]
6+
7+
8+
class CreateAccessTokenResponse(BaseModel):
9+
access_token: str
+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# File generated from our OpenAPI spec by Stainless.
2+
3+
from __future__ import annotations
4+
5+
import os
6+
7+
import pytest
8+
9+
from finch import Finch, AsyncFinch
10+
from finch.types import CreateAccessTokenResponse
11+
from tests.utils import assert_matches_type
12+
from finch._client import Finch, AsyncFinch
13+
14+
base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
15+
access_token = "My Access Token"
16+
17+
18+
class TestAccessTokens:
19+
strict_client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
20+
loose_client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=False)
21+
parametrize = pytest.mark.parametrize("client", [strict_client, loose_client], ids=["strict", "loose"])
22+
23+
@parametrize
24+
def test_method_create(self, client: Finch) -> None:
25+
access_token = client.access_tokens.create(
26+
client_id="<your_client_id>",
27+
client_secret="<your_client_secret>",
28+
code="<your_authorization_code>",
29+
redirect_uri="https://example.com",
30+
)
31+
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])
32+
33+
@parametrize
34+
def test_raw_response_create(self, client: Finch) -> None:
35+
response = client.access_tokens.with_raw_response.create(
36+
client_id="<your_client_id>",
37+
client_secret="<your_client_secret>",
38+
code="<your_authorization_code>",
39+
redirect_uri="https://example.com",
40+
)
41+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
42+
access_token = response.parse()
43+
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])
44+
45+
46+
class TestAsyncAccessTokens:
47+
strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
48+
loose_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=False)
49+
parametrize = pytest.mark.parametrize("client", [strict_client, loose_client], ids=["strict", "loose"])
50+
51+
@parametrize
52+
async def test_method_create(self, client: AsyncFinch) -> None:
53+
access_token = await client.access_tokens.create(
54+
client_id="<your_client_id>",
55+
client_secret="<your_client_secret>",
56+
code="<your_authorization_code>",
57+
redirect_uri="https://example.com",
58+
)
59+
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])
60+
61+
@parametrize
62+
async def test_raw_response_create(self, client: AsyncFinch) -> None:
63+
response = await client.access_tokens.with_raw_response.create(
64+
client_id="<your_client_id>",
65+
client_secret="<your_client_secret>",
66+
code="<your_authorization_code>",
67+
redirect_uri="https://example.com",
68+
)
69+
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
70+
access_token = response.parse()
71+
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])

0 commit comments

Comments
 (0)