Dan6erbond / sk-auth

Authentication library for use with SvelteKit featuring built-in OAuth providers and zero restriction customization!
MIT License
577 stars 70 forks source link

[Enhancement] Return access_token with user profile at end of OAuth flow #37

Closed benbarbersmith closed 3 years ago

benbarbersmith commented 3 years ago

Summary

This enhancement returns the user's access_token with user profile at end of the OAuth flow. I needed this in the process of migrating from Sapper and Passport to Svelte-kit and sk-auth in order to facilitate additional API calls after OAuth.

Context

Projects using OAuth often do so in order to acquire suitable access_tokens with specifically requested scopes.

For example, a project might use Google OAuth with the scopes https://www.googleapis.com/auth/youtube.upload and https://www.googleapis.com/auth/youtube in order to use the YouTube Data API on behalf of a user to check private information and upload videos.

sk-auth does not currently expose the user's access_token to Svelte-kit at the end of the OAuth flow.

Solution

This pull request makes it super easy to get the user's access_token by adding it to the profile object returned by getUserProfile.

Dan6erbond commented 3 years ago

Hi there, thanks for creating this pull request! This is actually done by design, in order to reduce clutter in the returned profile and enable proper typing.

SvelteKitAuth tokens differently. If you need access to the tokens returned by the initial getTokens() method, then you can make use of the profile() callback within the OAuth2Provider:

export interface OAuth2Tokens {
  access_token: string;
  token_type: string;
}

export type ProfileCallback<ProfileType = any, TokensType = any, ReturnType = any> = (
  profile: ProfileType,
  tokens: TokensType,
) => ReturnType | Promise<ReturnType>;

export interface OAuth2BaseProviderConfig<ProfileType = any, TokensType = any>
  extends ProviderConfig {
  profile?: ProfileCallback<ProfileType, TokensType>;
}

The callback receives the profile and tokens, and must return the profile which is then stored in the JWT.

The demo app actually does this to transform profiles and add provider information:

new GoogleOAuth2Provider({
  clientId: import.meta.env.VITE_GOOGLE_OAUTH_CLIENT_ID,
  clientSecret: import.meta.env.VITE_GOOGLE_OAUTH_CLIENT_SECRET,
  profile(profile) {
    return { ...profile, provider: "google" };
  },
}),

The callback can also be asynchronous, so if you want to include those in the actual profile or use them to make additional requests, you would do that in profile() which is similar to how NextAuth.js handles the OAuth flow.