Skip to content

feat(api): add method to create access token #249

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .stats.yml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
configured_endpoints: 23
configured_endpoints: 24
13 changes: 13 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ Methods:

- <code>client.<a href="./src/finch/_client.py">get_access_token</a>(\*args) -> str</code>
- <code>client.<a href="./src/finch/_client.py">get_auth_url</a>(\*args) -> str</code>
- <code>client.<a href="./src/finch/_client.py">with_access_token</a>(\*args) -> Self</code>

# AccessTokens

Types:

```python
from finch.types import CreateAccessTokenResponse
```

Methods:

- <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>

# HRIS

Expand Down
26 changes: 26 additions & 0 deletions src/finch/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@


class Finch(SyncAPIClient):
access_tokens: resources.AccessTokens
hris: resources.HRIS
providers: resources.Providers
account: resources.Account
Expand Down Expand Up @@ -135,6 +136,7 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)

self.access_tokens = resources.AccessTokens(self)
self.hris = resources.HRIS(self)
self.providers = resources.Providers(self)
self.account = resources.Account(self)
Expand Down Expand Up @@ -311,6 +313,16 @@ def get_auth_url(
)
)

def with_access_token(
self,
access_token: str,
) -> Self:
"""
Returns a copy of the current Finch client with the given access token for
authentication.
"""
return self.with_options(access_token=access_token)

@override
def _make_status_error(
self,
Expand Down Expand Up @@ -346,6 +358,7 @@ def _make_status_error(


class AsyncFinch(AsyncAPIClient):
access_tokens: resources.AsyncAccessTokens
hris: resources.AsyncHRIS
providers: resources.AsyncProviders
account: resources.AsyncAccount
Expand Down Expand Up @@ -430,6 +443,7 @@ def __init__(
_strict_response_validation=_strict_response_validation,
)

self.access_tokens = resources.AsyncAccessTokens(self)
self.hris = resources.AsyncHRIS(self)
self.providers = resources.AsyncProviders(self)
self.account = resources.AsyncAccount(self)
Expand Down Expand Up @@ -606,6 +620,16 @@ def get_auth_url(
)
)

def with_access_token(
self,
access_token: str,
) -> Self:
"""
Returns a copy of the current Finch client with the given access token for
authentication.
"""
return self.with_options(access_token=access_token)

@override
def _make_status_error(
self,
Expand Down Expand Up @@ -642,6 +666,7 @@ def _make_status_error(

class FinchWithRawResponse:
def __init__(self, client: Finch) -> None:
self.access_tokens = resources.AccessTokensWithRawResponse(client.access_tokens)
self.hris = resources.HRISWithRawResponse(client.hris)
self.providers = resources.ProvidersWithRawResponse(client.providers)
self.account = resources.AccountWithRawResponse(client.account)
Expand All @@ -651,6 +676,7 @@ def __init__(self, client: Finch) -> None:

class AsyncFinchWithRawResponse:
def __init__(self, client: AsyncFinch) -> None:
self.access_tokens = resources.AsyncAccessTokensWithRawResponse(client.access_tokens)
self.hris = resources.AsyncHRISWithRawResponse(client.hris)
self.providers = resources.AsyncProvidersWithRawResponse(client.providers)
self.account = resources.AsyncAccountWithRawResponse(client.account)
Expand Down
10 changes: 10 additions & 0 deletions src/finch/resources/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
from .account import Account, AsyncAccount, AccountWithRawResponse, AsyncAccountWithRawResponse
from .webhooks import Webhooks, AsyncWebhooks
from .providers import Providers, AsyncProviders, ProvidersWithRawResponse, AsyncProvidersWithRawResponse
from .access_tokens import (
AccessTokens,
AsyncAccessTokens,
AccessTokensWithRawResponse,
AsyncAccessTokensWithRawResponse,
)
from .request_forwarding import (
RequestForwarding,
AsyncRequestForwarding,
Expand All @@ -13,6 +19,10 @@
)

__all__ = [
"AccessTokens",
"AsyncAccessTokens",
"AccessTokensWithRawResponse",
"AsyncAccessTokensWithRawResponse",
"HRIS",
"AsyncHRIS",
"HRISWithRawResponse",
Expand Down
129 changes: 129 additions & 0 deletions src/finch/resources/access_tokens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# File generated from our OpenAPI spec by Stainless.

from __future__ import annotations

import httpx

from ..types import CreateAccessTokenResponse, access_token_create_params
from .._types import NOT_GIVEN, Body, Query, Headers, NotGiven
from .._utils import maybe_transform
from .._compat import cached_property
from .._resource import SyncAPIResource, AsyncAPIResource
from .._response import to_raw_response_wrapper, async_to_raw_response_wrapper
from .._base_client import (
make_request_options,
)

__all__ = ["AccessTokens", "AsyncAccessTokens"]


class AccessTokens(SyncAPIResource):
@cached_property
def with_raw_response(self) -> AccessTokensWithRawResponse:
return AccessTokensWithRawResponse(self)

def create(
self,
*,
client_id: str,
client_secret: str,
code: str,
redirect_uri: str,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> CreateAccessTokenResponse:
"""
Exchange the authorization code for an access token

Args:
extra_headers: Send extra headers

extra_query: Add additional query parameters to the request

extra_body: Add additional JSON properties to the request

timeout: Override the client-level default timeout for this request, in seconds
"""
return self._post(
"/auth/token",
body=maybe_transform(
{
"client_id": client_id,
"client_secret": client_secret,
"code": code,
"redirect_uri": redirect_uri,
},
access_token_create_params.AccessTokenCreateParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=CreateAccessTokenResponse,
)


class AsyncAccessTokens(AsyncAPIResource):
@cached_property
def with_raw_response(self) -> AsyncAccessTokensWithRawResponse:
return AsyncAccessTokensWithRawResponse(self)

async def create(
self,
*,
client_id: str,
client_secret: str,
code: str,
redirect_uri: str,
# Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs.
# The extra values given here take precedence over values defined on the client or passed to this method.
extra_headers: Headers | None = None,
extra_query: Query | None = None,
extra_body: Body | None = None,
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
) -> CreateAccessTokenResponse:
"""
Exchange the authorization code for an access token

Args:
extra_headers: Send extra headers

extra_query: Add additional query parameters to the request

extra_body: Add additional JSON properties to the request

timeout: Override the client-level default timeout for this request, in seconds
"""
return await self._post(
"/auth/token",
body=maybe_transform(
{
"client_id": client_id,
"client_secret": client_secret,
"code": code,
"redirect_uri": redirect_uri,
},
access_token_create_params.AccessTokenCreateParams,
),
options=make_request_options(
extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
),
cast_to=CreateAccessTokenResponse,
)


class AccessTokensWithRawResponse:
def __init__(self, access_tokens: AccessTokens) -> None:
self.create = to_raw_response_wrapper(
access_tokens.create,
)


class AsyncAccessTokensWithRawResponse:
def __init__(self, access_tokens: AsyncAccessTokens) -> None:
self.create = async_to_raw_response_wrapper(
access_tokens.create,
)
2 changes: 2 additions & 0 deletions src/finch/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@
from .provider import Provider as Provider
from .introspection import Introspection as Introspection
from .disconnect_response import DisconnectResponse as DisconnectResponse
from .access_token_create_params import AccessTokenCreateParams as AccessTokenCreateParams
from .create_access_token_response import CreateAccessTokenResponse as CreateAccessTokenResponse
from .request_forwarding_forward_params import RequestForwardingForwardParams as RequestForwardingForwardParams
from .request_forwarding_forward_response import RequestForwardingForwardResponse as RequestForwardingForwardResponse
17 changes: 17 additions & 0 deletions src/finch/types/access_token_create_params.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# File generated from our OpenAPI spec by Stainless.

from __future__ import annotations

from typing_extensions import Required, TypedDict

__all__ = ["AccessTokenCreateParams"]


class AccessTokenCreateParams(TypedDict, total=False):
client_id: Required[str]

client_secret: Required[str]

code: Required[str]

redirect_uri: Required[str]
9 changes: 9 additions & 0 deletions src/finch/types/create_access_token_response.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# File generated from our OpenAPI spec by Stainless.

from .._models import BaseModel

__all__ = ["CreateAccessTokenResponse"]


class CreateAccessTokenResponse(BaseModel):
access_token: str
71 changes: 71 additions & 0 deletions tests/api_resources/test_access_tokens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# File generated from our OpenAPI spec by Stainless.

from __future__ import annotations

import os

import pytest

from finch import Finch, AsyncFinch
from finch.types import CreateAccessTokenResponse
from tests.utils import assert_matches_type
from finch._client import Finch, AsyncFinch

base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010")
access_token = "My Access Token"


class TestAccessTokens:
strict_client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
loose_client = Finch(base_url=base_url, access_token=access_token, _strict_response_validation=False)
parametrize = pytest.mark.parametrize("client", [strict_client, loose_client], ids=["strict", "loose"])

@parametrize
def test_method_create(self, client: Finch) -> None:
access_token = client.access_tokens.create(
client_id="<your_client_id>",
client_secret="<your_client_secret>",
code="<your_authorization_code>",
redirect_uri="https://example.com",
)
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])

@parametrize
def test_raw_response_create(self, client: Finch) -> None:
response = client.access_tokens.with_raw_response.create(
client_id="<your_client_id>",
client_secret="<your_client_secret>",
code="<your_authorization_code>",
redirect_uri="https://example.com",
)
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
access_token = response.parse()
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])


class TestAsyncAccessTokens:
strict_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=True)
loose_client = AsyncFinch(base_url=base_url, access_token=access_token, _strict_response_validation=False)
parametrize = pytest.mark.parametrize("client", [strict_client, loose_client], ids=["strict", "loose"])

@parametrize
async def test_method_create(self, client: AsyncFinch) -> None:
access_token = await client.access_tokens.create(
client_id="<your_client_id>",
client_secret="<your_client_secret>",
code="<your_authorization_code>",
redirect_uri="https://example.com",
)
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])

@parametrize
async def test_raw_response_create(self, client: AsyncFinch) -> None:
response = await client.access_tokens.with_raw_response.create(
client_id="<your_client_id>",
client_secret="<your_client_secret>",
code="<your_authorization_code>",
redirect_uri="https://example.com",
)
assert response.http_request.headers.get("X-Stainless-Lang") == "python"
access_token = response.parse()
assert_matches_type(CreateAccessTokenResponse, access_token, path=["response"])