updated OAuthProvider types

This commit is contained in:
Ewout Stortenbeker 2022-05-20 14:44:20 +02:00
parent 0a53ea0bad
commit 9de89b2a2e
8 changed files with 43 additions and 27 deletions

View file

@ -1,4 +1,4 @@
import { IOAuth2Provider, IOAuth2ProviderSettings, IOAuth2AuthCodeParams, IOAuth2RefreshTokenParams } from "./oauth-provider";
import { IOAuth2ProviderSettings, IOAuth2AuthCodeParams, IOAuth2RefreshTokenParams, OAuth2Provider, OAuth2ProviderInitInfo } from "./oauth-provider";
import { fetch } from '../shared/simple-fetch';
/**
@ -48,9 +48,10 @@ interface IDropboxUser {
}
team_member_id?: string
}
export class DropboxAuthProvider implements IOAuth2Provider {
export class DropboxAuthProvider extends OAuth2Provider {
constructor(private settings: IDropboxAuthSettings) {
constructor(settings: IDropboxAuthSettings) {
super(settings);
if (!settings.scopes) { settings.scopes = []; }
if (settings.scopes.length > 0 && !settings.scopes.includes('account_info.read')) { settings.scopes.push('account_info.read'); }
}
@ -66,7 +67,7 @@ export class DropboxAuthProvider implements IOAuth2Provider {
* @param info.options.locale If the locale specified is a supported language, Dropbox will direct users to a translated version of the authorization website. Locale tags should be IETF language tags.
* @param info.options.force_reauthentication When true (default is false) users will be signed out if they are currently signed in. This will make sure the user is brought to a page where they can create a new account or sign in to another account. This should only be used when there is a definite reason to believe that the user needs to sign in to a new or different account.
*/
async init(info: { redirect_url: string, state?: string, options?: { locale?: string, require_role?: string, disable_signup?: boolean, force_reapprove?: boolean, force_reauthentication?: boolean } }) {
async init(info: OAuth2ProviderInitInfo) {
// Return url to get authorization code with
const options = info.options || {};
const authUrl = `https://www.dropbox.com/oauth2/authorize?response_type=code&token_access_type=offline&client_id=${this.settings.client_id}&scope=${encodeURIComponent(this.settings.scopes.join(' '))}&redirect_uri=${encodeURIComponent(info.redirect_url)}&locale=${options.locale || ''}&require_role=${options.require_role || ''}&force_reauthentication=${options.force_reauthentication === true}&force_reapprove=${options.force_reapprove === true}&disable_signup=${options.disable_signup === true}&state=${encodeURIComponent(info.state)}`;

View file

@ -1,4 +1,4 @@
import { IOAuth2Provider, IOAuth2ProviderSettings, IOAuth2AuthCodeParams, IOAuth2RefreshTokenParams } from "./oauth-provider";
import { IOAuth2ProviderSettings, IOAuth2AuthCodeParams, IOAuth2RefreshTokenParams, OAuth2Provider, OAuth2ProviderInitInfo } from "./oauth-provider";
import { fetch } from '../shared/simple-fetch';
/**
@ -28,9 +28,10 @@ interface IFacebookUser {
}
}
}
export class FacebookAuthProvider implements IOAuth2Provider {
export class FacebookAuthProvider extends OAuth2Provider {
constructor(private settings: IFacebookAuthSettings) {
constructor(settings: IFacebookAuthSettings) {
super(settings);
if (!settings.scopes) { settings.scopes = []; }
if (!settings.scopes.includes('email')) { settings.scopes.push('email'); }
}
@ -40,7 +41,7 @@ export class FacebookAuthProvider implements IOAuth2Provider {
* @param info.redirectUrl Url spotify will redirect to after authorizing, should be the url
* @param info.state Optional state that will be passed to redirectUri by spotify
*/
async init(info: { redirect_url: string, state?: string }) {
async init(info: OAuth2ProviderInitInfo) {
// Return url to get authorization code with
const authUrl = `https://www.facebook.com/v7.0/dialog/oauth?response_type=code&client_id=${this.settings.client_id}&scope=${encodeURIComponent(this.settings.scopes.join(' '))}&redirect_uri=${encodeURIComponent(info.redirect_url)}&state=${encodeURIComponent(info.state)}`;
return authUrl;

View file

@ -1,4 +1,4 @@
import { IOAuth2Provider, IOAuth2ProviderSettings, IOpenIDToken, IOpenIDConfiguration, IOAuth2AuthCodeParams, IOAuth2RefreshTokenParams } from "./oauth-provider";
import { IOAuth2ProviderSettings, IOpenIDToken, IOpenIDConfiguration, IOAuth2AuthCodeParams, IOAuth2RefreshTokenParams, OAuth2ProviderInitInfo, OAuth2Provider } from "./oauth-provider";
import { fetch } from '../shared/simple-fetch';
/**
@ -43,11 +43,12 @@ interface IGoogleUser {
updated_at: number
}
export class GoogleAuthProvider implements IOAuth2Provider {
export class GoogleAuthProvider extends OAuth2Provider {
_config: IOpenIDConfiguration
constructor(private settings: IGoogleAuthSettings) {
constructor(settings: IGoogleAuthSettings) {
super(settings);
if (!settings.scopes) { settings.scopes = []; }
if (!settings.scopes.includes('email')) { settings.scopes.push('email'); }
if (!settings.scopes.includes('profile')) { settings.scopes.push('profile'); }
@ -66,7 +67,7 @@ export class GoogleAuthProvider implements IOAuth2Provider {
* @param info.redirectUrl Url spotify will redirect to after authorizing, should be the url
* @param info.state Optional state that will be passed to redirectUri by spotify
*/
async init(info: { redirect_url: string, state?: string }) {
async init(info: OAuth2ProviderInitInfo) {
// Return url to get authorization code with
// See https://developers.google.com/identity/protocols/oauth2/web-server#httprest

View file

@ -2,6 +2,7 @@ import { DropboxAuthProvider } from './dropbox';
import { FacebookAuthProvider } from './facebook';
import { GoogleAuthProvider } from './google';
import { InstagramAuthProvider } from './instagram';
import { OAuth2Provider } from './oauth-provider';
import { SpotifyAuthProvider } from './spotify';
export { DropboxAuthProvider, IDropboxAuthSettings } from './dropbox';
@ -10,7 +11,7 @@ export { GoogleAuthProvider, IGoogleAuthSettings } from './google';
export { InstagramAuthProvider, IInstagramAuthSettings } from './instagram';
export { SpotifyAuthProvider, ISpotifyAuthSettings } from './spotify';
const oAuth2Providers = {
const oAuth2Providers: { [key: string]: typeof OAuth2Provider } = {
dropbox: DropboxAuthProvider,
facebook: FacebookAuthProvider,
google: GoogleAuthProvider,

View file

@ -1,4 +1,4 @@
import { IOAuth2Provider, IOAuth2ProviderSettings, IOAuth2AuthCodeParams } from "./oauth-provider";
import { IOAuth2ProviderSettings, IOAuth2AuthCodeParams, OAuth2Provider, OAuth2ProviderInitInfo } from "./oauth-provider";
import { fetch } from '../shared/simple-fetch';
/**
@ -28,9 +28,10 @@ interface IInstagramUser {
followed_by: number
}
}
export class InstagramAuthProvider implements IOAuth2Provider {
export class InstagramAuthProvider extends OAuth2Provider {
constructor(private settings: IInstagramAuthSettings) {
constructor(settings: IInstagramAuthSettings) {
super(settings);
if (!settings.scopes) { settings.scopes = []; }
if (!settings.scopes.includes('basic')) { settings.scopes.push('basic'); }
@ -44,7 +45,7 @@ export class InstagramAuthProvider implements IOAuth2Provider {
* @param info.redirectUrl Url spotify will redirect to after authorizing, should be the url
* @param info.state Optional state that will be passed to redirectUri by spotify
*/
async init(info: { redirect_url: string, state?: string }) {
async init(info: OAuth2ProviderInitInfo) {
// Return url to get authorization code with
// See https://www.instagram.com/developer/authorization/
const authUrl = `https://api.instagram.com/oauth/authorize/?response_type=code&client_id=${this.settings.client_id}&scope=${encodeURIComponent(this.settings.scopes.join(' '))}&redirect_uri=${encodeURIComponent(info.redirect_url)}&state=${encodeURIComponent(info.state)}`;

View file

@ -18,10 +18,20 @@ export interface IOAuth2TokenResult {
expires_in?: number,
refresh_token?: string
}
export interface IOAuth2Provider {
init(info: { redirect_url: string, state?: string, options?: any }): Promise<string>
getAccessToken(params: IOAuth2AuthCodeParams | IOAuth2RefreshTokenParams): Promise<IOAuth2TokenResult>
getUserInfo(access_token: string): Promise<{ id: string, name: string, display_name: string, picture?: Array<{ width?: number, height?: number, url: string }>, email: string, email_verified: boolean, other?: { [key:string]: string|number|boolean } }>
export type OAuth2ProviderInitInfo = { redirect_url: string, state?: string, options?: any };
export type OAuth2ProviderUserInfo = { id: string, name: string, display_name: string, picture?: Array<{ width?: number, height?: number, url: string }>, email: string, email_verified: boolean, other?: { [key:string]: string|number|boolean } };
// export interface IOAuth2Provider {
// init(info: OAuth2ProviderInitInfo): Promise<string>;
// getAccessToken(param: OAuth2ProviderGetAccessTokenParams): Promise<IOAuth2TokenResult>;
// getUserInfo(access_token: string): Promise<OAuth2ProviderUserInfo>;
// }
class NotImplementedError extends Error { constructor() { super('Not implemented'); } }
export class OAuth2Provider { //implements IOAuth2Provider
constructor(protected settings: IOAuth2ProviderSettings) {}
init(info: OAuth2ProviderInitInfo): Promise<string> { throw new NotImplementedError(); };
getAccessToken(param: IOAuth2AuthCodeParams|IOAuth2RefreshTokenParams): Promise<IOAuth2TokenResult> { throw new NotImplementedError(); };;
getUserInfo(access_token: string): Promise<OAuth2ProviderUserInfo> { throw new NotImplementedError(); };;
}
// For OAuth2.0 providers with id_token in getAccessToken, see https://auth0.com/docs/tokens/concepts/jwts
export interface IOpenIDToken {

View file

@ -1,4 +1,4 @@
import { IOAuth2Provider, IOAuth2ProviderSettings, IOAuth2AuthCodeParams, IOAuth2RefreshTokenParams } from "./oauth-provider";
import { IOAuth2ProviderSettings, IOAuth2AuthCodeParams, IOAuth2RefreshTokenParams, OAuth2Provider, OAuth2ProviderInitInfo } from "./oauth-provider";
import { fetch } from '../shared/simple-fetch';
/**
@ -28,9 +28,10 @@ interface ISpotifyUser {
type: 'user',
uri: string
}
export class SpotifyAuthProvider implements IOAuth2Provider {
export class SpotifyAuthProvider extends OAuth2Provider {
constructor(private settings: ISpotifyAuthSettings) {
constructor(settings: ISpotifyAuthSettings) {
super(settings);
if (!settings.scopes) { settings.scopes = []; }
if (!settings.scopes.includes('user-read-email')) { settings.scopes.push('user-read-email'); }
if (!settings.scopes.includes('user-read-private')) { settings.scopes.push('user-read-private'); }
@ -41,7 +42,7 @@ export class SpotifyAuthProvider implements IOAuth2Provider {
* @param info.redirectUrl Url spotify will redirect to after authorizing
* @param info.state Optional state that will be passed to redirectUri by spotify
*/
async init(info: { redirect_url: string, state?: string }) {
async init(info: OAuth2ProviderInitInfo) {
// Return url to get authorization code with
const authUrl = `https://accounts.spotify.com/authorize?response_type=code&client_id=${this.settings.client_id}&scope=${encodeURIComponent(this.settings.scopes.join(' '))}&redirect_uri=${encodeURIComponent(info.redirect_url)}&state=${encodeURIComponent(info.state)}`;
return authUrl;

View file

@ -4,7 +4,7 @@ import type { AceBaseServerConfig } from '../settings';
import type { DbUserAccountDetails } from '../schema/user';
import type { ConnectedClient } from './clients';
import type { DebugLogger, SimpleCache } from 'acebase-core';
import type { IOAuth2Provider } from '../oauth-providers/oauth-provider';
import type { OAuth2Provider } from '../oauth-providers/oauth-provider';
import type { Server as HttpServer } from 'http';
import type { Server as SecureHttpServer } from 'https';
import type { PathBasedRules } from '../rules';
@ -23,7 +23,7 @@ export interface RouteInitEnvironment {
tokenSalt: string;
clients: Map<string, ConnectedClient>;
authCache: SimpleCache<string, DbUserAccountDetails>;
authProviders: { [providerName: string]: IOAuth2Provider };
authProviders: { [providerName: string]: OAuth2Provider };
rules: PathBasedRules
};