0
# Installation Storage
1
2
Flexible storage system for persisting and retrieving Slack app installation data including tokens, team information, user details, and enterprise organization data.
3
4
## Capabilities
5
6
### InstallationStore Interface
7
8
Interface for storing and retrieving installation data with support for multiple storage backends.
9
10
```typescript { .api }
11
/**
12
* Interface for storing and retrieving installation data
13
*/
14
interface InstallationStore {
15
/**
16
* Store installation data after successful OAuth flow
17
* @param installation - Complete installation data from OAuth response
18
* @param logger - Optional logger for debugging
19
*/
20
storeInstallation<AuthVersion extends "v1" | "v2">(
21
installation: Installation<AuthVersion, boolean>,
22
logger?: Logger
23
): Promise<void>;
24
25
/**
26
* Fetch installation data for API authorization
27
* @param query - Query parameters to identify installation
28
* @param logger - Optional logger for debugging
29
* @returns Installation data including tokens and metadata
30
*/
31
fetchInstallation(
32
query: InstallationQuery<boolean>,
33
logger?: Logger
34
): Promise<Installation<"v1" | "v2", boolean>>;
35
36
/**
37
* Delete installation data (optional method)
38
* @param query - Query parameters to identify installation to delete
39
* @param logger - Optional logger for debugging
40
*/
41
deleteInstallation?(
42
query: InstallationQuery<boolean>,
43
logger?: Logger
44
): Promise<void>;
45
}
46
```
47
48
### Installation Data Types
49
50
Complete installation data structure supporting both OAuth versions and enterprise installations.
51
52
```typescript { .api }
53
/**
54
* Complete installation data structure
55
*/
56
interface Installation<
57
AuthVersion extends "v1" | "v2" = "v1" | "v2",
58
IsEnterpriseInstall extends boolean = boolean
59
> {
60
/** Team/workspace information (undefined for enterprise-wide installs) */
61
team: IsEnterpriseInstall extends true
62
? undefined
63
: {
64
id: string;
65
name?: string;
66
};
67
68
/** Enterprise organization information (when applicable) */
69
enterprise: IsEnterpriseInstall extends true ? EnterpriseInfo : EnterpriseInfo | undefined;
70
71
/** User installation data */
72
user: {
73
token: AuthVersion extends "v1" ? string : string | undefined;
74
refreshToken?: AuthVersion extends "v1" ? never : string | undefined;
75
expiresAt?: AuthVersion extends "v1" ? never : number | undefined;
76
scopes: AuthVersion extends "v1" ? string[] : string[] | undefined;
77
id: string;
78
};
79
80
/** Bot installation data */
81
bot?: {
82
token: string;
83
refreshToken?: string;
84
expiresAt?: number;
85
scopes: string[];
86
id: string;
87
userId: string;
88
};
89
90
/** Incoming webhook configuration */
91
incomingWebhook?: {
92
url: string;
93
channel?: string;
94
channelId?: string;
95
configurationUrl?: string;
96
};
97
98
/** App ID (OAuth v2 only) */
99
appId?: AuthVersion extends "v2" ? string : undefined;
100
101
/** Token type when bot user exists */
102
tokenType?: "bot";
103
104
/** Enterprise organization URL (OAuth v2 only) */
105
enterpriseUrl?: AuthVersion extends "v2" ? string : undefined;
106
107
/** Whether this is an enterprise-wide installation */
108
isEnterpriseInstall?: IsEnterpriseInstall;
109
110
/** OAuth version used for this installation */
111
authVersion?: AuthVersion;
112
113
/** Metadata passed through OAuth flow */
114
metadata?: string;
115
}
116
117
/**
118
* Enterprise organization information
119
*/
120
interface EnterpriseInfo {
121
id: string;
122
name?: string;
123
}
124
125
/**
126
* Type alias for enterprise organization installation
127
*/
128
type OrgInstallation = Installation<"v2", true>;
129
```
130
131
### InstallationQuery Types
132
133
Query parameters for fetching installation data.
134
135
```typescript { .api }
136
/**
137
* Query parameters for fetching installation data
138
*/
139
interface InstallationQuery<isEnterpriseInstall extends boolean = boolean> {
140
/** Team ID for workspace-specific queries (required for workspace installs) */
141
teamId: isEnterpriseInstall extends false ? string : undefined;
142
/** Enterprise ID for organization queries (required for enterprise installs) */
143
enterpriseId: isEnterpriseInstall extends true ? string : string | undefined;
144
/** User ID for user-specific queries */
145
userId?: string;
146
/** Conversation ID for context-specific queries */
147
conversationId?: string;
148
/** Whether this is an enterprise-wide installation query (required) */
149
isEnterpriseInstall: isEnterpriseInstall;
150
}
151
152
/**
153
* Type alias for enterprise organization installation queries
154
*/
155
type OrgInstallationQuery = InstallationQuery<true>;
156
```
157
158
### Built-in Installation Stores
159
160
Ready-to-use implementations of the InstallationStore interface.
161
162
#### MemoryInstallationStore
163
164
```typescript { .api }
165
/**
166
* In-memory installation store for development and testing
167
* WARNING: Data is lost when process restarts
168
*/
169
class MemoryInstallationStore implements InstallationStore {
170
constructor();
171
172
async storeInstallation<AuthVersion extends "v1" | "v2">(
173
installation: Installation<AuthVersion, boolean>,
174
logger?: Logger
175
): Promise<void>;
176
177
async fetchInstallation(
178
query: InstallationQuery<boolean>,
179
logger?: Logger
180
): Promise<Installation<"v1" | "v2", boolean>>;
181
182
async deleteInstallation(
183
query: InstallationQuery<boolean>,
184
logger?: Logger
185
): Promise<void>;
186
}
187
```
188
189
#### FileInstallationStore
190
191
```typescript { .api }
192
/**
193
* File-based installation store for simple persistent storage
194
*/
195
class FileInstallationStore implements InstallationStore {
196
/**
197
* @param options - Configuration options for file storage
198
*/
199
constructor(options?: FileInstallationOptions);
200
201
async storeInstallation<AuthVersion extends "v1" | "v2">(
202
installation: Installation<AuthVersion, boolean>,
203
logger?: Logger
204
): Promise<void>;
205
206
async fetchInstallation(
207
query: InstallationQuery<boolean>,
208
logger?: Logger
209
): Promise<Installation<"v1" | "v2", boolean>>;
210
211
async deleteInstallation(
212
query: InstallationQuery<boolean>,
213
logger?: Logger
214
): Promise<void>;
215
}
216
217
/**
218
* Configuration options for FileInstallationStore
219
*/
220
interface FileInstallationOptions {
221
/** Base directory to store installation files */
222
baseDir?: string;
223
/** Whether to store historical installation data */
224
historicalDataEnabled?: boolean;
225
/** Client ID for organizing installations by app */
226
clientId?: string;
227
}
228
```
229
230
**Usage Examples:**
231
232
```typescript
233
import {
234
InstallProvider,
235
MemoryInstallationStore,
236
FileInstallationStore,
237
Installation,
238
InstallationQuery
239
} from "@slack/oauth";
240
241
// Using memory store (development)
242
const memoryStore = new MemoryInstallationStore();
243
const installer = new InstallProvider({
244
clientId: process.env.SLACK_CLIENT_ID!,
245
clientSecret: process.env.SLACK_CLIENT_SECRET!,
246
stateSecret: "secret",
247
installationStore: memoryStore,
248
});
249
250
// Using file store (simple persistence)
251
const fileStore = new FileInstallationStore("./slack-installations");
252
const installer2 = new InstallProvider({
253
clientId: process.env.SLACK_CLIENT_ID!,
254
clientSecret: process.env.SLACK_CLIENT_SECRET!,
255
stateSecret: "secret",
256
installationStore: fileStore,
257
});
258
259
// Custom installation store implementation
260
class DatabaseInstallationStore implements InstallationStore {
261
async storeInstallation(installation: Installation) {
262
// Store in database
263
await db.installations.create({
264
teamId: installation.team?.id,
265
enterpriseId: installation.enterprise?.id,
266
botToken: installation.bot?.token,
267
userToken: installation.user?.token,
268
// ... other fields
269
});
270
}
271
272
async fetchInstallation(query: InstallationQuery) {
273
// Fetch from database
274
const record = await db.installations.findOne({
275
teamId: query.teamId,
276
enterpriseId: query.enterpriseId,
277
});
278
279
if (!record) {
280
throw new Error("Installation not found");
281
}
282
283
return {
284
team: record.teamId ? { id: record.teamId } : undefined,
285
enterprise: record.enterpriseId ? { id: record.enterpriseId } : undefined,
286
bot: record.botToken ? {
287
token: record.botToken,
288
scopes: record.botScopes || [],
289
id: record.botId,
290
userId: record.botUserId,
291
} : undefined,
292
user: record.userToken ? {
293
token: record.userToken,
294
scopes: record.userScopes || [],
295
id: record.userId,
296
} : undefined,
297
};
298
}
299
300
async deleteInstallation(query: InstallationQuery) {
301
await db.installations.deleteOne({
302
teamId: query.teamId,
303
enterpriseId: query.enterpriseId,
304
});
305
}
306
}
307
308
// Direct installation store usage
309
const query: InstallationQuery = {
310
teamId: "T1234567890",
311
isEnterpriseInstall: false,
312
};
313
314
const installation = await installer.installationStore.fetchInstallation(query);
315
console.log("Bot token:", installation.bot?.token);
316
```