pilcrowOnPaper / arctic

OAuth 2.0 clients for popular providers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

RFC: Base types

rmarscher opened this issue · comments

Summary

A few interfaces and an abstract Provider class would help give a small amount of structure and uniformity to the providers while still staying flexible.

Suggested Types

This could be added at src/types.ts -

export interface OAuth2Credentials {
	clientId: string;
	clientSecret?: string;
}

export interface OAuth2Tokens {
	accessToken: string;
	accessTokenExpiresAt: Date;
	refreshToken: string | null;
}

export interface OAuth2TokensWithIdToken<_TokenClaims> extends OAuth2Tokens {
	idToken: string;
	idTokenClaims: _TokenClaims;
}

export interface JWTTokenClaims {
	iss: string;
	sub: string;
	aud: string;
	iat: number;
	exp: number;
}

interface ProviderInterface<_Credentials, _Tokens> {
	createAuthorizationURL(state: string): Promise<URL>;
	validateAuthorizationCode(code: string): Promise<unknown>;
	refreshAccessToken(refreshToken: string): Promise<Omit<_Tokens, "refreshToken">>;
	getUser?: (accessToken: string) => Promise<unknown>;
}

export abstract class Provider<_Credentials = OAuth2Credentials, _Tokens = OAuth2Tokens>
	implements ProviderInterface<_Credentials, _Tokens>
{
	constructor(
		_credentials: _Credentials,
		_options?: {
			redirectURI: string;
			responseMode?: "query" | "form_post";
			scope?: string[];
		}
	) {}
	abstract createAuthorizationURL(state: string): Promise<URL>;
	abstract validateAuthorizationCode(code: string): Promise<_Tokens>;
	abstract refreshAccessToken(refreshToken: string): Promise<Omit<_Tokens, "refreshToken">>;
}

export abstract class ProviderWithGetUser<
	_Credentials = OAuth2Credentials,
	_Tokens = OAuth2Tokens,
	_User = unknown
> extends Provider<_Credentials, _Tokens> {
	abstract getUser(refreshToken: string): Promise<_User>;
}

Usage

Here are some example updates to existing provider constructors and types. The rest of the class definitions should continue to work as they are currently defined.

export interface AppleIdTokenClaims extends JWTTokenClaims {
	iss: "https://appleid.apple.com";
	email?: string;
	email_verified?: boolean;
	is_private_email?: boolean;
	real_user_status: 0 | 1 | 2;
	transfer_sub?: string;
}

export type AppleTokens = OAuth2TokensWithIdToken<AppleIdTokenClaims>;
export type AppleRefreshedTokens = Omit<AppleTokens, "refreshToken">;

export interface AppleCredentials {
	clientId: string;
	teamId: string;
	keyId: string;
	certificate: string;
}

export class Apple implements Provider {
	// ...

	constructor(
		credentials: AppleCredentials,
		options?: {
			redirectURI?: string;
			responseMode?: "query" | "form_post";
			scope?: string[];
		}
	) {
		// ...
	}
	
	// ...
}
export interface GoogleTokens extends OAuth2Tokens {
	accessToken: string;
	refreshToken: string | null;
	accessTokenExpiresAt: Date;
}

export type GoogleRefreshedTokens = Omit<GoogleTokens, "refreshToken">;

export class Google implements ProviderWithGetUser {
	// ...

	constructor(
		{
			clientId,
			clientSecret
		}: OAuth2Credentials,
		options?: {
			redirectURI?: string;
			scope?: string[];
			accessType?: "online" | "offline";
		}
	) {
		// ...
	}

	// ...
}

I've been following along and updating a project to lucia v3 beta, oslo and arctic. If you can add these generic types and reduce some of the differences, it would make it easier in userland when supporting with multiple providers. If you are interested, I can probably prepare a PR for you. Thanks for all of the work on these libraries.

Some of these are already provided by oslo/oauth2 so I should re-export them

0.4.0 exports OAuth2Provider and OAuth2ProviderWithPKCE interfaces