Skip to content
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

Refreshing token support built in? #110

Open
developer992 opened this issue Dec 14, 2023 · 6 comments
Open

Refreshing token support built in? #110

developer992 opened this issue Dec 14, 2023 · 6 comments
Labels
enhancement New feature or request
Milestone

Comments

@developer992
Copy link

developer992 commented Dec 14, 2023

Hello,

I am implementing SAP XSUAA Oauth2 via GenericSSO client and it works, good job!

I also receive back a refresh token after successful login

According to docs, refreshing the token involves creating a new request like so:

Refresh Token Grant

If the current access token is expired, a new one can be requested with the [Refresh Token  flow](https://docs.cloudfoundry.org/api/uaa/version/74.23.0/index.html#refresh-token).

Make a request:

POST https://[xsuaa.url]/oauth/token

Headers
Accept: application/json
Content-Type: application/x-www-form-urlencoded

client_id=[xsuaa.clientid]
client_secret=[xsuaa.clientsecret]
refresh_token=[refresh_token]
grant_type=refresh_token

Check the response:

{
  "access_token": [access_token],
  "token_type": "bearer",
  "id_token": [...],
  "refresh_token": [refresh_token],
  "expires_in": [...],
  "scope": [...],
  "jti": [...]
}

Congratulation, you now have a refreshed access_token.

I would like to know if this support is already built in or do we need to manually do this request?

Many thanks!

@developer992 developer992 changed the title How do i refresh token? Refreshing token support built in? Dec 15, 2023
@developer992
Copy link
Author

I rolled my own implementation, here's the code if anyone is interested.

class SAPXsuaaSSO(SSOBase):
    provider = "sap.xsuaa"
    scope = settings.DEFAULT_SCOPE

    async def get_discovery_document(self) -> DiscoveryDocument:
        return {
            "authorization_endpoint": f"{settings.XSUAA_API_URL}/oauth/authorize/",
            "token_endpoint": f"{settings.XSUAA_API_URL}/oauth/token/",
            "userinfo_endpoint": f"{settings.XSUAA_API_URL}/userinfo",
        }

    async def openid_from_response(self, response: dict, session: Optional[httpx.AsyncClient] = None) -> OpenID:
        return OpenIDUser(**response)

    async def token_refresh(self, refresh_token: str) -> OpenID:

        token_url, headers, body = self.oauth_client.prepare_refresh_token_request(
            token_url=await self.token_endpoint,
            refresh_token=refresh_token,
            scope=self.scope,

        )

        auth = httpx.BasicAuth(self.client_id, self.client_secret)
        async with httpx.AsyncClient() as session:
            response = await session.post(token_url, headers=headers, content=body, auth=auth)
            content = response.json()
            self._refresh_token = content.get("refresh_token")
            self.oauth_client.parse_request_body_response(json.dumps(content))
            uri, headers, _ = self.oauth_client.add_token(await self.userinfo_endpoint)
            response = await session.get(uri, headers=headers)
            content = response.json()

        return await self.openid_from_response(content, session)

@developer992
Copy link
Author

Thanks.

@tomasvotava
Copy link
Owner

@developer992 Hi and thanks for both the question and the solution! I am sorry I didn't have the time to come up with it before you did.

It's actually a good idea to bake the support for refreshing token in, I'll look into it over the holidays!

@developer992
Copy link
Author

Thank you man, happy new year as well :)

@Mulugruntz
Copy link

Hi @tomasvotava !
If you found the time to investigate, do we know if this is something that could be baked in FastAPI-SSO?

Warm regards,

@tomasvotava
Copy link
Owner

Hi @Mulugruntz, the thing is the same SSO instance may currently be used to authenticate multiple users, so it would be insecure to continue reusing it in the future to refresh access tokens as well, e.g. this flow would be IMHO common and very bad:

  • user A logs in (verify_and_process is called, refresh_token on SSO instance belongs to user A)
  • user B logs in (verify_and_process is called, refresh_token on SSO instance belongs to user B)
  • user A get their token refreshed (using user B's refresh token)

This would no more be an edge-case race condition, but rather a buggy implementation. I have a rather large refactor in mind, that will forever sort out all race conditions (and, I presume, introduce some new ones 😁). After it's done, fastapi-sso will be more generic with granular control over token and OpenIDs, then I'd say it would only be natural that it will also be able to refresh tokens for you.

I know there were lots of promises from me and the time flies and nothing happens, I am sorry, I think you all know it yourselves, there are loads of work everywhere, I just need to find the time 🙏

@tomasvotava tomasvotava added the enhancement New feature or request label Nov 4, 2024
@tomasvotava tomasvotava added this to the 1.0.0 milestone Nov 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants