Skip to content

Commit c528ea0

Browse files
committed
Add OAuth-2 login via GitHub to query SlideRuleEarth membership #866
1 parent a78e56d commit c528ea0

File tree

2 files changed

+25
-31
lines changed

2 files changed

+25
-31
lines changed

web-client/src/components/SrUserInfo.vue

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,13 @@ const org = computed(() => githubAuthStore.org)
1111
const isOrgMember = computed(() => githubAuthStore.isOrgMember)
1212
const isOrgOwner = computed(() => githubAuthStore.isOrgOwner)
1313
const teams = computed(() => githubAuthStore.teams)
14-
const teamRoles = computed(() => githubAuthStore.teamRoles)
1514
const orgRoles = computed(() => githubAuthStore.orgRoles)
16-
const accessibleClusters = computed(() => githubAuthStore.accessibleClusters)
15+
const knownClusters = computed(() => githubAuthStore.knownClusters)
1716
const deployableClusters = computed(() => githubAuthStore.deployableClusters)
1817
1918
// Token metadata from store state (provided separately by server for UX)
2019
const maxNodes = computed(() => githubAuthStore.maxNodes)
21-
const clusterTtlHours = computed(() => githubAuthStore.clusterTtlHours)
20+
const maxTTL = computed(() => githubAuthStore.maxTTL)
2221
const tokenIssuedAt = computed(() => githubAuthStore.tokenIssuedAtDate)
2322
const tokenExpiresAt = computed(() => githubAuthStore.tokenExpiresAt)
2423
const tokenIssuer = computed(() => githubAuthStore.tokenIssuer)
@@ -62,22 +61,11 @@ const isAuthenticated = computed(() => githubAuthStore.authStatus === 'authentic
6261
<span v-else>{{ orgRoles.join(', ') }}</span>
6362
</td>
6463
</tr>
65-
<tr>
66-
<td class="sr-user-label">Team Roles:</td>
67-
<td class="sr-user-value">
68-
<span v-if="Object.keys(teamRoles).length === 0" class="sr-no-value">None</span>
69-
<div v-else class="sr-team-roles">
70-
<div v-for="(role, team) in teamRoles" :key="team" class="sr-team-role">
71-
{{ team }}: {{ role }}
72-
</div>
73-
</div>
74-
</td>
75-
</tr>
7664
<tr>
7765
<td class="sr-user-label">Accessible Clusters:</td>
7866
<td class="sr-user-value">
79-
<span v-if="accessibleClusters.length === 0" class="sr-no-value">None</span>
80-
<span v-else>{{ accessibleClusters.join(', ') }}</span>
67+
<span v-if="knownClusters.length === 0" class="sr-no-value">None</span>
68+
<span v-else>{{ knownClusters.join(', ') }}</span>
8169
</td>
8270
</tr>
8371
<tr>
@@ -94,7 +82,7 @@ const isAuthenticated = computed(() => githubAuthStore.authStatus === 'authentic
9482
<tr>
9583
<td class="sr-user-label">Deployed Cluster's TTL:</td>
9684
<td class="sr-user-value">
97-
{{ clusterTtlHours != null ? `${clusterTtlHours} hours` : 'N/A' }}
85+
{{ maxTTL != null ? `${maxTTL} minutes` : 'N/A' }}
9886
</td>
9987
</tr>
10088
<tr>

web-client/src/stores/githubAuthStore.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ export const useGitHubAuthStore = defineStore('githubAuth', {
1818
teams: [] as string[],
1919
teamRoles: {} as Record<string, string>,
2020
orgRoles: [] as string[],
21-
accessibleClusters: [] as string[],
21+
knownClusters: [] as string[],
2222
deployableClusters: [] as string[],
2323
token: null as string | null,
2424
lastError: null as string | null,
2525
authTimestamp: null as number | null,
2626
// Token metadata (returned separately from server, not decoded from JWT)
2727
org: null as string | null,
2828
maxNodes: null as number | null,
29-
clusterTtlHours: null as number | null,
29+
maxTTL: null as number | null,
3030
tokenIssuedAt: null as number | null, // Unix timestamp
3131
tokenExpiresAtTimestamp: null as number | null, // Unix timestamp
3232
tokenIssuer: null as string | null,
@@ -108,9 +108,9 @@ export const useGitHubAuthStore = defineStore('githubAuth', {
108108
isInTeam: (state) => (teamSlug: string) => state.teams.includes(teamSlug),
109109

110110
/**
111-
* Check if user can access a specific cluster
111+
* Check if this is a known cluster and should be shown in the UI
112112
*/
113-
isAccessibleCluster: (state) => (cluster: string) => state.accessibleClusters.includes(cluster),
113+
isKnownCluster: (state) => (cluster: string) => state.knownClusters.includes(cluster),
114114

115115
/**
116116
* Get formatted expiration time from stored token metadata
@@ -176,7 +176,13 @@ export const useGitHubAuthStore = defineStore('githubAuth', {
176176
logger.debug('Stored return path', { path: window.location.pathname })
177177

178178
// Build the login URL - the Lambda will handle the redirect to GitHub
179-
const loginUrl = new URL(`${apiUrl}/auth/github/login`)
179+
// Use the current hostname to determine the domain (e.g., testsliderule.org, slideruleearth.io)
180+
const hostname = window.location.hostname
181+
// Extract base domain from hostname (e.g., "client.testsliderule.org" -> "testsliderule.org")
182+
const domainParts = hostname.split('.')
183+
const domain = domainParts.length > 2 ? domainParts.slice(-2).join('.') : hostname
184+
185+
const loginUrl = new URL(`https://login.${domain}/auth/github/login`)
180186
loginUrl.searchParams.set('state', state)
181187
// Pass the frontend callback URL so Lambda knows where to redirect back
182188
loginUrl.searchParams.set('redirect_uri', window.location.origin)
@@ -201,14 +207,14 @@ export const useGitHubAuthStore = defineStore('githubAuth', {
201207
teams?: string
202208
teamRoles?: string
203209
orgRoles?: string
204-
accessibleClusters?: string
210+
knownClusters?: string
205211
deployableClusters?: string
206212
token?: string
207213
error?: string
208214
// Token metadata (returned separately, not decoded from JWT)
209215
org?: string
210216
maxNodes?: string
211-
clusterTtlHours?: string
217+
maxTTL?: string
212218
tokenIssuedAt?: string
213219
tokenExpiresAt?: string
214220
tokenIssuer?: string
@@ -237,8 +243,8 @@ export const useGitHubAuthStore = defineStore('githubAuth', {
237243
this.teams = params.teams ? params.teams.split(',').filter((t) => t) : []
238244
this.teamRoles = params.teamRoles ? JSON.parse(params.teamRoles) : {}
239245
this.orgRoles = params.orgRoles ? params.orgRoles.split(',').filter((r) => r) : []
240-
this.accessibleClusters = params.accessibleClusters
241-
? params.accessibleClusters.split(',').filter((c) => c)
246+
this.knownClusters = params.knownClusters
247+
? params.knownClusters.split(',').filter((c) => c)
242248
: []
243249
this.deployableClusters = params.deployableClusters
244250
? params.deployableClusters.split(',').filter((c) => c)
@@ -252,7 +258,7 @@ export const useGitHubAuthStore = defineStore('githubAuth', {
252258
// Store token metadata (provided separately by server for UX)
253259
this.org = params.org || null
254260
this.maxNodes = params.maxNodes ? parseInt(params.maxNodes, 10) : null
255-
this.clusterTtlHours = params.clusterTtlHours ? parseInt(params.clusterTtlHours, 10) : null
261+
this.maxTTL = params.maxTTL ? parseInt(params.maxTTL, 10) : null
256262
this.tokenIssuedAt = params.tokenIssuedAt ? parseInt(params.tokenIssuedAt, 10) : null
257263
this.tokenExpiresAtTimestamp = params.tokenExpiresAt
258264
? parseInt(params.tokenExpiresAt, 10)
@@ -266,11 +272,11 @@ export const useGitHubAuthStore = defineStore('githubAuth', {
266272
teams: this.teams,
267273
teamRoles: this.teamRoles,
268274
orgRoles: this.orgRoles,
269-
accessibleClusters: this.accessibleClusters,
275+
knownClusters: this.knownClusters,
270276
deployableClusters: this.deployableClusters,
271277
hasToken: !!this.token,
272278
maxNodes: this.maxNodes,
273-
clusterTtlHours: this.clusterTtlHours
279+
maxTTL: this.maxTTL
274280
})
275281

276282
return true
@@ -287,7 +293,7 @@ export const useGitHubAuthStore = defineStore('githubAuth', {
287293
this.teams = []
288294
this.teamRoles = {}
289295
this.orgRoles = []
290-
this.accessibleClusters = []
296+
this.knownClusters = []
291297
this.deployableClusters = []
292298
this.token = null
293299
this.authTimestamp = null
@@ -296,7 +302,7 @@ export const useGitHubAuthStore = defineStore('githubAuth', {
296302
// Clear token metadata
297303
this.org = null
298304
this.maxNodes = null
299-
this.clusterTtlHours = null
305+
this.maxTTL = null
300306
this.tokenIssuedAt = null
301307
this.tokenExpiresAtTimestamp = null
302308
this.tokenIssuer = null

0 commit comments

Comments
 (0)