Skip to content

Commit 58d0331

Browse files
Merge branch 'ChurchApps:main' into main
2 parents 69de135 + 476af01 commit 58d0331

File tree

2 files changed

+22
-16
lines changed

2 files changed

+22
-16
lines changed

src/modules/membership/auth/AuthenticatedUser.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export class AuthenticatedUser extends BaseAuthenticatedUser {
8181
);
8282
}
8383

84-
public static getCombinedApiJwt(user: User, userChurch: LoginUserChurch) {
84+
public static getCombinedApiJwt(user: User, userChurch: LoginUserChurch, expiresIn?: string) {
8585
const permList: string[] = [];
8686

8787
userChurch.apis?.forEach((api) => {
@@ -97,7 +97,7 @@ export class AuthenticatedUser extends BaseAuthenticatedUser {
9797
const leaderGroupIds: string[] = [];
9898
userChurch.groups?.forEach((g) => { if (g.leader) leaderGroupIds.push(g.id); });
9999

100-
const options: SignOptions = { expiresIn: Environment.jwtExpiration as any };
100+
const options: SignOptions = { expiresIn: (expiresIn || Environment.jwtExpiration) as any };
101101
return jwt.sign(
102102
{
103103
id: user.id,

src/modules/membership/controllers/OAuthController.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,14 @@ export class OAuthController extends MembershipBaseController {
8282
return this.handleDeviceCodeGrant(device_code, client_id, res);
8383
}
8484

85-
// All other grant types require client_secret validation
86-
const client = (await this.repos.oAuthClient.loadByClientIdAndSecret(client_id, client_secret)) as any;
85+
// Validate client: require client_secret for all grant types except refresh_token
86+
// (public clients like device-flow TV apps may not have a client_secret)
87+
let client;
88+
if (grant_type === "refresh_token" && !client_secret) {
89+
client = (await this.repos.oAuthClient.loadByClientId(client_id)) as any;
90+
} else {
91+
client = (await this.repos.oAuthClient.loadByClientIdAndSecret(client_id, client_secret)) as any;
92+
}
8793
if (!client) return this.json({ error: "invalid_client" }, 400);
8894

8995
if (grant_type === "authorization_code") {
@@ -120,14 +126,14 @@ export class OAuthController extends MembershipBaseController {
120126
await UserHelper.replaceDomainAdminPermissions([loginUserChurch]);
121127
UserHelper.addAllReportingPermissions([loginUserChurch]);
122128

123-
// Create access token
129+
// Create access token (refresh token expires in 90 days)
124130
const token: OAuthToken = {
125131
clientId: client.clientId,
126132
userChurchId: authCode.userChurchId,
127-
accessToken: AuthenticatedUser.getCombinedApiJwt(user, loginUserChurch),
133+
accessToken: AuthenticatedUser.getCombinedApiJwt(user, loginUserChurch, "7 days"),
128134
refreshToken: UniqueIdHelper.shortId(),
129135
scopes: authCode.scopes,
130-
expiresAt: new Date(Date.now() + 60 * 60 * 1000 * 12) // 12 hours
136+
expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) // 90 days
131137
};
132138
await this.repos.oAuthToken.save(token);
133139

@@ -137,7 +143,7 @@ export class OAuthController extends MembershipBaseController {
137143
return this.json({
138144
access_token: token.accessToken,
139145
token_type: "Bearer",
140-
expires_in: 3600 * 12,
146+
expires_in: 7 * 24 * 3600, // 7 days (matches JWT expiration)
141147
created_at: Math.floor(Date.now() / 1000),
142148
refresh_token: token.refreshToken,
143149
scope: token.scopes
@@ -172,14 +178,14 @@ export class OAuthController extends MembershipBaseController {
172178
await UserHelper.replaceDomainAdminPermissions([loginUserChurch]);
173179
UserHelper.addAllReportingPermissions([loginUserChurch]);
174180

175-
// Create new access token with proper JWT
181+
// Create new access token (refresh token expires in 90 days)
176182
const token: OAuthToken = {
177183
clientId: client.clientId,
178184
userChurchId: oldToken.userChurchId,
179-
accessToken: AuthenticatedUser.getCombinedApiJwt(user, loginUserChurch),
185+
accessToken: AuthenticatedUser.getCombinedApiJwt(user, loginUserChurch, "7 days"),
180186
refreshToken: UniqueIdHelper.shortId(),
181187
scopes: oldToken.scopes,
182-
expiresAt: new Date(Date.now() + 60 * 60 * 1000 * 12) // 12 hours
188+
expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) // 90 days
183189
};
184190
await this.repos.oAuthToken.save(token);
185191

@@ -189,7 +195,7 @@ export class OAuthController extends MembershipBaseController {
189195
access_token: token.accessToken,
190196
token_type: "Bearer",
191197
created_at: Math.floor(Date.now() / 1000),
192-
expires_in: 3600 * 12,
198+
expires_in: 7 * 24 * 3600, // 7 days (matches JWT expiration)
193199
refresh_token: token.refreshToken,
194200
scope: token.scopes
195201
});
@@ -310,17 +316,17 @@ export class OAuthController extends MembershipBaseController {
310316
UserHelper.addAllReportingPermissions([loginUserChurch]);
311317

312318
// Create access token
313-
const accessToken = AuthenticatedUser.getCombinedApiJwt(user, loginUserChurch);
319+
const accessToken = AuthenticatedUser.getCombinedApiJwt(user, loginUserChurch, "7 days");
314320
const refreshToken = UniqueIdHelper.shortId();
315321

316-
// Store the refresh token for later use
322+
// Store the refresh token (expires in 90 days)
317323
const token: OAuthToken = {
318324
clientId: dc.clientId,
319325
userChurchId: dc.userChurchId,
320326
accessToken,
321327
refreshToken,
322328
scopes: dc.scopes,
323-
expiresAt: new Date(Date.now() + 60 * 60 * 1000 * 12) // 12 hours
329+
expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000) // 90 days
324330
};
325331
await this.repos.oAuthToken.save(token);
326332

@@ -330,7 +336,7 @@ export class OAuthController extends MembershipBaseController {
330336
return this.json({
331337
access_token: accessToken,
332338
token_type: "Bearer",
333-
expires_in: 3600 * 12, // 12 hours
339+
expires_in: 7 * 24 * 3600, // 7 days (matches JWT expiration)
334340
refresh_token: refreshToken,
335341
scope: dc.scopes
336342
});

0 commit comments

Comments
 (0)