Skip to content

OAuth Authentication ​

The module auth-oauth provides general OAuth Authentication, with built-in support for GitHub and other OAuth providers. It also supports mock user login in the development environment, making development and debugging very convenient.

How to Use ​

1. Login ​

typescript
class ControllerStudent {
  @Web.get('login')
  @Passport.public()
  async login() {
    await this.bean.auth.authenticate('auth-oauth:oauth', { clientName: 'github', state: { redirect: '/' } });
  }
}

2. Logout ​

typescript
await this.bean.passport.signout();

3. Authentication Credentials ​

Set the authentication credentials in App Config.

src/backend/config/config/config.ts

typescript
// onions
config.onions = {
  authProvider: {
    'auth-oauth:oauth': {
      clients: {
        github: {
          clientID: 'xxxxxx',
          clientSecret: 'xxxxxxx',
        },
      },
    },
  },
};
  • clients.github: A Provider can set multiple Clients, currently built-in with github

4. Adding New OAuth Client Credentials ​

Taking google as an example:

  1. Install the corresponding Strategy npm package
bash
$ pnpm add passport-google-oauth20 -w
  1. Add Client type definitions using the interface merging mechanism

In VSCode editor, enter the code snippet recordauthclient to automatically generate the code skeleton:

typescript
declare module 'vona-module-x-x' {
  export interface IAuthProvider_xxx_ClientRecord {
    : never;
  }
}

Adjust the code:

typescript
declare module 'vona-module-auth-oauth' {
  export interface IAuthProviderOauthClientRecord {
    google: never;
  }
}
  1. Set the authentication credentials in App Config and specify the corresponding Strategy
typescript
import StrategyGoogle from 'passport-google-oauth20';

// onions
config.onions = {
  authProvider: {
    'auth-oauth:oauth': {
      clients: {
        google: {
          Strategy: StrategyGoogle,
          clientID: 'xxxxxx',
          clientSecret: 'xxxxxxx',
        },
      },
    },
  },
};

5. OAuth Authentication Callback URL ​

When using OAuth authentication, you need to provide the system's Callback URL on the OAuth website.

VonaJS provides a unified Callback URL value and outputs it directly to the console during development for easy use.

6. Disable useMockForDev ​

By default, mocking user login is allowed in the development environment.

useMockForDev can be disabled in App Config.

src/backend/config/config/config.ts

typescript
// onions
config.onions = {
  authProvider: {
    'auth-oauth:oauth': {
      useMockForDev: false,
    },
  },
};

Source Code Analysis ​

This section analyzes the core source code of the module auth-oauth to illustrate how to develop an OAuth2-based Auth Provider.

For example, creating an Auth Provider: oauth in the module auth-oauth

1. CLI Command ​

bash
$ vona :create:bean authProvider oauth --module=auth-oauth

2. Menu Command ​

TIP

Context Menu - [Module Path]: Vona Bean/Auth Provider

Auth Provider Definition ​

typescript
export interface IAuthProviderOauthClientOptionsGithub extends IAuthProviderOauth2ClientOptions {
  userProfileURL?: string;
  userAgent?: string;
}

export interface IAuthProviderOauthClientRecord extends IAuthProviderClientRecord {
  github: IAuthProviderOauthClientOptionsGithub;
}

export interface IAuthProviderOauthClientOptions extends IAuthProviderOauth2ClientOptions {
  Strategy?: Constructable<StrategyBase>;
}

export interface IAuthProviderOptionsOauth extends IDecoratorAuthProviderOptions<
  IAuthProviderOauthClientRecord,
  IAuthProviderOauthClientOptions
> {}

@AuthProvider<IAuthProviderOptionsOauth>({
  base: {
    confirmed: true,
    clientID: 'Shoule specify clientID',
    clientSecret: 'Shoule specify clientSecret',
  },
  clients: {
    github: {
      Strategy: StrategyGithub,
    },
  },
})
class AuthProviderOauth extends BeanAuthProviderOauth2Base {
  async strategy(
    clientOptions: IAuthProviderOauthClientOptions,
    _options: IAuthProviderOptionsOauth,
  ): Promise<Constructable<StrategyBase>> {
    if (!clientOptions.Strategy) throw new Error('Should specify Strategy for oauth provider');
    return clientOptions.Strategy;
  }
}
  • IAuthProviderOauthClientRecord: Defines multiple Clients, with built-in github Client definition
  • IAuthProviderOauthClientOptions: Defines Client options, where the Strategy field specifies the OAuth authentication strategy
  • IAuthProviderOptionsOauth: Defines the parameters of the Auth Provider
  • strategy: Returns the authentication strategy based on the Strategy configured in the Client
  • verify: Provided by the base class BeanAuthProviderOauth2Base by default, uses the utility method getStrategyOauth2Profile to extract Profile data from the authentication result and returns it to the system

Custom OAuth Strategy ​

The module auth-oauth uses the Strategy field to specify the OAuth authentication strategy, allowing flexible support for different OAuth providers.

  • Built-in strategy: The module has a built-in github Client configuration with the passport-github strategy

  • Adding a new strategy: Taking google as an example, the following steps are required

  1. Install the corresponding Strategy npm package
bash
$ pnpm add passport-google-oauth20 -w
  1. Add a new Client type definition using the interface merging mechanism
typescript
declare module 'vona-module-auth-oauth' {
  export interface IAuthProviderOauthClientRecord {
    google: IAuthProviderOauth2ClientOptions;
  }
}
  1. Specify the corresponding Strategy in App Config
typescript
import StrategyGoogle from 'passport-google-oauth20';

// onions
config.onions = {
  authProvider: {
    'auth-oauth:oauth': {
      clients: {
        google: {
          Strategy: StrategyGoogle,
          clientID: 'xxxxxx',
          clientSecret: 'xxxxxxx',
        },
      },
    },
  },
};

Profile ​

  1. The Provider's verify only needs to return Profile data. The system will generate a User object based on the Profile data
  2. The Profile contains an id field value
  3. The OAuth provider ensures that a unique id value is generated for each different user

Profile has a unified interface definition:

typescript
export interface IAuthUserProfile {
  id: string;
  username?: string;
  displayName?: string;
  name?: IAuthUserProfileName;
  gender?: string; // male/female
  profileUrl?: string;
  emails?: IAuthUserProfilePropSlice[];
  photos?: IAuthUserProfilePropSlice[];
  locale?: keyof ILocaleRecord;
  confirmed?: boolean;
}
  • confirmed: If true, it means the user has confirmed and no further activation operation is needed

Released under the MIT License.