Skip to content

Commit

Permalink
Merge pull request #1287 from FoalTS/abstract-provider-type
Browse files Browse the repository at this point in the history
Improve `AbstractProvider.getUserInfoFromTokens` return type
  • Loading branch information
LoicPoullain authored Aug 22, 2024
2 parents aacc37a + b292a5f commit e1941d1
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 15 deletions.
2 changes: 2 additions & 0 deletions docs/blog/version-5.0-release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ Version 5.0 of [Foal](https://foalts.org/) is out!
```
- The return value of the social services `getUserInfoFromTokens` method is now typed.
## Removal of deprecated components
- The deprecated hook `@Log` has been removed. Use the `Logger` service in a custom `@Hook` instead.
Expand Down
8 changes: 6 additions & 2 deletions docs/docs/authentication/social-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,11 @@ export interface GithubUserInfoParameter {
// ...
}

export class GithubProvider extends AbstractProvider<GithubAuthParameter, GithubUserInfoParameter> {
export interface GithubUserInfo {
// ...
}

export class GithubProvider extends AbstractProvider<GithubAuthParameter, GithubUserInfoParameter, GithubUserInfo> {

protected configPaths = {
clientId: 'social.github.clientId',
Expand All @@ -357,7 +361,7 @@ export class GithubProvider extends AbstractProvider<GithubAuthParameter, Github

protected defaultScopes: string[] = [ 'email' ]; // Optional

async getUserInfoFromTokens(tokens: SocialTokens, params?: GithubUserInfoParameter) {
getUserInfoFromTokens(tokens: SocialTokens, params?: GithubUserInfoParameter): GithubUserInfo | Promise<GithubUserInfo> {
// ...

// In case the server returns an error when requesting
Expand Down
15 changes: 9 additions & 6 deletions packages/social/src/abstract-provider.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,16 @@ describe('TokenError', () => {

describe('AbstractProvider', () => {

class ConcreteProvider extends AbstractProvider<any, any> {
class ConcreteProvider extends AbstractProvider<any, any, any> {
protected configPaths = {
clientId: 'settings.social.example.clientId',
clientSecret: 'settings.social.example.clientSecret',
redirectUri: 'settings.social.example.redirectUri'
};
protected authEndpoint = 'https://example2.com/auth';
protected tokenEndpoint = 'http://localhost:3000/token';
getUserInfoFromTokens(tokens: SocialTokens) {

async getUserInfoFromTokens(tokens: SocialTokens): Promise<any> {
throw new Error('Method not implemented.');
}
}
Expand Down Expand Up @@ -611,7 +612,7 @@ describe('AbstractProvider', () => {
});

class ConcreteProvider2 extends ConcreteProvider {
getUserInfoFromTokens(tokens: SocialTokens) {
async getUserInfoFromTokens(tokens: SocialTokens) {
// Do not throw an error.
}
}
Expand Down Expand Up @@ -656,7 +657,7 @@ describe('AbstractProvider', () => {
let calledWithTokens: null|SocialTokens = null;
let calledWithParams: null|any = null;
class ConcreteProvider2 extends ConcreteProvider {
getUserInfoFromTokens(tokens: SocialTokens, params?: any) {
async getUserInfoFromTokens(tokens: SocialTokens, params?: any) {
calledWithTokens = tokens;
calledWithParams = params || null;
}
Expand Down Expand Up @@ -718,7 +719,8 @@ describe('Abstract Provider With PKCE', () => {
protected usePKCE: boolean = true;
protected authEndpoint = 'https://example2.com/auth';
protected tokenEndpoint = 'http://localhost:3000/token';
getUserInfoFromTokens(tokens: SocialTokens) {

async getUserInfoFromTokens(tokens: SocialTokens) {
throw new Error('Method not implemented.');
}
}
Expand Down Expand Up @@ -917,7 +919,8 @@ describe('Abstract Provider With PKCE and Plain Method', () => {
protected useCodeVerifierAsCodeChallenge = true;
protected authEndpoint = 'https://example2.com/auth';
protected tokenEndpoint = 'http://localhost:3000/token';
getUserInfoFromTokens(tokens: SocialTokens) {

async getUserInfoFromTokens(tokens: SocialTokens) {
throw new Error('Method not implemented.');
}
}
Expand Down
11 changes: 5 additions & 6 deletions packages/social/src/abstract-provider.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ export interface ObjectType {
* @class AbstractProvider
* @template AuthParameters - Additional parameters to pass to the auth endpoint.
* @template UserInfoParameters - Additional parameters to pass when retrieving user information.
* @template IUserInfo - Type of the user information.
* @template UserInfo - Type of the user information.
*/
export abstract class AbstractProvider<AuthParameters extends ObjectType, UserInfoParameters extends ObjectType, IUserInfo = any> {
export abstract class AbstractProvider<AuthParameters extends ObjectType, UserInfoParameters extends ObjectType, UserInfo = any> {

/**
* Configuration paths from which the client ID, client secret and redirect URI must be retrieved.
Expand Down Expand Up @@ -232,10 +232,10 @@ export abstract class AbstractProvider<AuthParameters extends ObjectType, UserIn
* @abstract
* @param {SocialTokens} tokens - Tokens returned by the authorization server. It contains at least an access token.
* @param {UserInfoParameters} [params] - Additional parameters to pass to the function.
* @returns {*} The user information.
* @returns {UserInfo | Promise<UserInfo>} The user information.
* @memberof AbstractProvider
*/
abstract getUserInfoFromTokens(tokens: SocialTokens, params?: UserInfoParameters): any;
abstract getUserInfoFromTokens(tokens: SocialTokens, params?: UserInfoParameters): UserInfo | Promise<UserInfo>;

/**
* Returns an HttpResponseOK or HttpResponseRedirect object to redirect the user to the social provider's authorization page.
Expand Down Expand Up @@ -393,13 +393,12 @@ export abstract class AbstractProvider<AuthParameters extends ObjectType, UserIn
*
* It retrieves the access token as well as the user information.
*
* @template UserInfo
* @param {Context} ctx - The request context.
* @param {UserInfoParameters} [params] - Additional parameters to pass to the function.
* @returns {Promise<UserInfoAndTokens<UserInfo>>} The access token and the user information
* @memberof AbstractProvider
*/
async getUserInfo<UserInfo extends IUserInfo>(ctx: Context, params?: UserInfoParameters): Promise<UserInfoAndTokens<UserInfo>> {
async getUserInfo(ctx: Context, params?: UserInfoParameters): Promise<UserInfoAndTokens<UserInfo>> {
const tokens = await this.getTokens(ctx);
const userInfo = await this.getUserInfoFromTokens(tokens, params);
return { userInfo, tokens };
Expand Down
2 changes: 1 addition & 1 deletion packages/social/src/google-provider.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class GoogleProvider extends AbstractProvider<GoogleAuthParams, never, Go

protected defaultScopes: string[] = [ 'openid', 'profile', 'email' ];

getUserInfoFromTokens(tokens: SocialTokens): object {
getUserInfoFromTokens(tokens: SocialTokens): GoogleUserInfo {
try {
const encodedPayload = tokens.id_token.split('.')[1];
const decodedPayload = Buffer.from(convertBase64urlToBase64(encodedPayload), 'base64')
Expand Down

0 comments on commit e1941d1

Please sign in to comment.