pilcrowOnPaper / arctic

OAuth 2.0 clients for popular providers
MIT License
886 stars 58 forks source link

RFC: Use methods to get tokens #145

Closed pilcrowOnPaper closed 3 months ago

pilcrowOnPaper commented 3 months ago

I'm currently planning to update Arctic to v2, which will use the new @oslojs/oauth package.

Right now, access tokens are stored in a regular object:

const tokens = await github.validateAuthorizationCode(code);
const accessToken = tokens.accessToken;

The proposal is to use methods to access data instead:

const tokens = await github.validateAuthorizationCode(code);
const accessToken = tokens.accessToken();

Here, tokens is a Tokens instance. This class wraps around the raw JSON-parsed body and the accessToken() methods returns an access token if it exists or throws an error. Since every method either returns a value or throws, you no longer have to deal with null. We can make OpenID Connect optional too.

const tokens = await github.validateAuthorizationCode(code);
if (tokens.hasRefreshToken) {
  const refreshToken = tokens.refreshToken();
  // We can assume `refresh_token_expires_in` exists because of the if check
  const refreshTokenExpiresAt = tokens.refreshTokenExpiresAt();
}

// throws if oidc scope isn't used
const idToken = tokens.idToken();

Another benefit is that you can manually parse the response if the provider returns additional data.

const tokens = await github.validateAuthorizationCode(code);
const data = tokens.raw();
if ("userId" in data && typeof data.userId === "string) {
  const userId = data.userId;
}

Using methods also allows us to add alternative methods for expiration, like accessTokenExpiresInSeconds() alongside accessTokenExpiresAt().

But the biggest benefit here is that every provider can use the same Tokens class, which would cut off a lot of code. There is a downside that you can accidentally attempt to access fields that's never returned by the provider, but I personally don't see that as a major issue.

const refreshToken = tokens.refreshToken(); // GitHub doesn't return a refresh token
pilcrowOnPaper commented 3 months ago

RFC accepted