Skip to content

oauth

Add OAuth functionality to your extension to access resources from a service on the user’s behalf. The Alt. app currently only support PKCE flow. To see if a provider is supporting PKCE flow, check if there is a code_challenge and code_verifier on their OAuth doc.

Functions

oauth.createPKCE

createPKCE(provider: OAuthProvider): OAuthPKCEClient

Create PKCE client.

Classes

OAuthPKCEClient

abstract class OAuthPKCEClient {
abstract removeToken(): Promise<void>;
abstract startAuth(): Promise<OAuthPKCERequest>;
abstract getToken(): Promise<OAuthTokenStorageValue | null>;
abstract setToken(token: OAuthToken | OAuthTokenResponse): Promise<OAuthTokenStorageValue>;
}

OAuthPKCEClient.startAuth

startAuth(): Promise<OAuthPKCERequest>;

Start the OAuth authorization.

OAuthPKCEClient.getToken

getToken(): Promise<OAuthTokenStorageValue | null>;

Get the stored OAuth token.

OAuthPKCEClient.setToken

setToken(token: OAuthToken | OAuthTokenResponse): Promise<OAuthTokenStorageValue>;

Store the OAuth token.

OAuthPKCEClient.removeToken

removeToken(): Promise<void>

Remove the OAuth token.

Example

Spotify OAuth

import { _extension } from '@altdot/extension';
const SPOTIFY_CLIENT_ID = 'CLIENT_ID';
const spotifyClient = _extension.oAuth.createPKCE({
key: 'spotify-oauth',
name: 'Spotify',
icon: 'spotify-logo',
description: 'Connect your Spotify account',
client: {
scope: 'user-read-email',
clientId: SPOTIFY_CLIENT_ID,
authorizeUrl: 'https://accounts.spotify.com/authorize',
},
});
async function refreshToken(refreshToken: string) {
const fetchResponse = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: SPOTIFY_CLIENT_ID,
}),
});
const tokenResponse = await fetchResponse.json();
const token = await spotifyClient.setToken(tokenResponse);
return token;
}
async function startAuth() {
const response = await spotifyClient.startAuth();
// Exchange auth code
const response = await fetch('https://accounts.spotify.com/api/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
code: response.code,
client_id: SPOTIFY_CLIENT_ID,
grant_type: 'authorization_code',
redirect_uri: response.redirectUri,
code_verifier: response.codeVerifier,
}),
});
const tokenResponse = await response.json();
const token = await spotifyClient.setToken(tokenResponse);
return token;
}
export default async function Command() {
let token = await spotifyClient.getToken();
if (!token || !token.refreshToken) {
token = await startAuth();
} else if (Date.now() >= token.expiresTimestamp) {
token = await refreshToken(token.refreshToken);
}
console.log(token.accessToken);
}

Google OAuth

To use PKCE flow with Google OAuth, you must select the iOS application type when creating a new OAuth client ID.

import { _extension } from '@altdot/extension';
const GOOGLE_CLIENT_ID = 'CLIENT_ID';
const googleClient = _extension.oAuth.createPKCE({
client: {
clientId: GOOGLE_CLIENT_ID,
redirectMethod: _extension.OAuth.OAuthRedirect.AppUrl,
authorizeUrl: 'https://accounts.google.com/o/oauth2/v2/auth',
scope: 'https://www.googleapis.com/auth/drive.metadata.readonly',
},
key: 'google-drive',
icon: 'google-drive',
name: 'Google Drive',
});
async function refreshToken(refreshToken: string) {
const response = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: GOOGLE_CLIENT_ID,
}),
});
const tokenResponse = await response.json();
const token = await googleClient.setToken(tokenResponse);
return token;
}
async function startAuth() {
const response = await googleClient.startAuth();
// Exchange auth code
const fetchResponse = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
code: response.code,
client_id: GOOGLE_CLIENT_ID,
grant_type: 'authorization_code',
redirect_uri: response.redirectUri,
code_verifier: response.codeVerifier,
}),
});
const tokenResponse = await fetchResponse.json();
const token = await googleClient.setToken(tokenResponse);
return token;
}
export default async function Command() {
let token = await googleClient.getToken();
if (!token || !token.refreshToken) {
token = await startAuth();
} else if (Date.now() >= token.expiresTimestamp) {
token = await refreshToken(token.refreshToken);
}
console.log(token.accessToken);
}

Types

oauth.OAuthPKCEClientOptions

The options when creating a PKCE client.

interface OAuthPKCEClientOptions {
scope: string;
clientId: string;
authorizeUrl: string;
redirectMethod?: OAuthRedirect;
extraParams?: Record<string, string>;
}
PropertyTypeDescription
scopestringThe OAuth client’s scope
clientIdstringThe OAuth client Id
authorizeUrlstringThe authorization URL of the OAuth service provider
redirectMethodOAuthRedirectThe OAuth redirect method. Default to Web
extraParams?Record<string, string>Additional parameters to be added in the authorization URL

OAuthRedirect

Redirect methods for the OAuth flow

enum OAuthRedirect {
Web = 'web',
AppUrl = 'app-url',
DeepLink = 'deep-link',
}
NameDescription
WebConfigure /oauth/redirect/extension as the redirect URL in the OAuth provider.
AppUrlConfigure com.altdot-app:/oauth2callback as the redirect URL in the OAuth provider.
DeepLinkConfigure altdot-app://oauth/redirect as the redirect URL in the OAuth provider.

oauth.OAuthProvider

The options for creating an OAuth provider.

interface OAuthProvider {
key: string;
name: string;
icon: string;
description?: string;
documentationUrl?: string;
client: OAuthPKCEClientOptions;
}
PropertyTypeDescription
keystringUnique id for the provider
namestringName of the provider that will be displayed to the user
iconstringIcon of the provider
description?stringShort description of the provider
documentationUrl?stringURL to the provider documentation
clientOAuthPKCEClientOptionsThe OAuth client data

oauth.OAuthPKCERequest

Value returned by the startAuth method

interface OAuthPKCERequest {
code: string;
redirectUri: string;
codeVerifier: string;
codeChallenge: string;
}
PropertyTypeDescription
codestringCode from the OAuth provider
redirectUristringThe OAuth’s redirect uri
codeVerifierstringThe PKCE code verifier
codeChallengestringThe PKCE code challenge

oauth.OAuthToken

Contains information about the OAuth token

interface OAuthToken {
scope?: string;
expiresIn?: number;
accessToken: string;
refreshToken?: string;
}
PropertyTypeDescription
accessTokenstringThe OAuth’s access token
scope?stringThe OAuth’s scope
expiresIn?numberThe lifetime in seconds of the access token
refreshToken?stringThe OAuth’s refresh token

oauth.OAuthTokenStorageValue

Contains information about the stored OAuth token in storage.

interface OAuthTokenStorageValue extends OAuthToken {
expiresTimestamp: number;
}
PropertyTypeDescription
accessTokenstringThe OAuth’s access token
expiresTimestampnumberThe expires timestamp of the access token
scope?stringThe OAuth’s scope
expiresIn?numberThe lifetime in seconds of the access token
refreshToken?stringThe OAuth’s refresh token

oauth.OAuthTokenResponse

Standard response when making an OAuth token request

interface OAuthTokenResponse {
scope?: string;
expires_in?: number;
access_token: string;
refresh_token?: string;
}
PropertyTypeDescription
access_tokenstringThe OAuth’s access token
scope?stringThe OAuth’s scope
expires_in?numberThe lifetime in seconds of the access token
refresh_token?stringThe OAuth’s refresh token