fastapi-sso icon indicating copy to clipboard operation
fastapi-sso copied to clipboard

Refreshing token support built in?

Open developer992 opened this issue 1 year ago • 4 comments

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 avatar Dec 14 '23 12:12 developer992

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 avatar Dec 18 '23 09:12 developer992

Thanks.

developer992 avatar Dec 20 '23 11:12 developer992

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

tomasvotava avatar Dec 22 '23 09:12 tomasvotava

Thank you man, happy new year as well :)

developer992 avatar Jan 04 '24 07:01 developer992