Skip to content

Commit 8928aa9

Browse files
committed
create OAuthClientRepository + client utils
1 parent a759a6d commit 8928aa9

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

packages/api/src/oauth2/index.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type { GrantIdentifier, OAuthClient, OAuthClientRepository } from '@jmondi/oauth2-server'
2+
import { getClient, clientExists, clientHasGrantType } from 'src/oauth2/utils'
3+
class SendOAuthClientRepository implements OAuthClientRepository {
4+
/**
5+
* Gets client from client id
6+
* @param {string} identifier - client identifier (`client_id`)
7+
* @returns {Promise<OAuthClient>} - OAuthClient object
8+
*/
9+
async getByIdentifier(identifier: string): Promise<OAuthClient> {
10+
return await getClient(identifier)
11+
}
12+
13+
/**
14+
* Checks if the client is valid. The client is valid if:
15+
* - The client exists
16+
* - AND the client is authorized for the requested grant type
17+
* @param {GrantIdentifier} grantType - requested grant type
18+
* @param {OAuthClient} client - client
19+
* @param {string | undefined} clientSecret - client secret (not required as we are using PKCE) @see {https://tsoauth2server.com/docs/grants/authorization_code}
20+
* @returns {Promise<boolean>}
21+
*/
22+
async isClientValid(
23+
grantType: GrantIdentifier,
24+
client: OAuthClient,
25+
clientSecret?: string
26+
): Promise<boolean> {
27+
const doesClientExist = await clientExists(client.id)
28+
if (!doesClientExist) {
29+
return false
30+
}
31+
const clientHasAuthorizationGrantType: boolean = await clientHasGrantType(client.id, grantType)
32+
if (!clientHasAuthorizationGrantType) {
33+
return false
34+
}
35+
return true
36+
}
37+
}

packages/api/src/oauth2/types.ts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export interface OAuthScope {
2+
name: string
3+
[key: string]: string
4+
}

packages/api/src/oauth2/utils.ts

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import type { GrantIdentifier, OAuthClient } from '@jmondi/oauth2-server'
2+
import { supabaseAdmin } from 'app/utils/supabase/admin'
3+
import debug from 'debug'
4+
import type { OAuthScope } from 'src/oauth2/types'
5+
6+
const logger = debug.log
7+
8+
export const getClient = async (clientId: string): Promise<OAuthClient> => {
9+
try {
10+
const { data, error } = await supabaseAdmin
11+
.from('oauth2_clients')
12+
.select('*')
13+
.eq('client_id', clientId)
14+
.single()
15+
if (error) {
16+
logger(error)
17+
throw error
18+
}
19+
return {
20+
id: data.client_id,
21+
name: data.client_name,
22+
redirectUris: [data.redirect_uri],
23+
allowedGrants: await getClientGrants(clientId),
24+
scopes: await getClientScopes(clientId),
25+
}
26+
} catch (error) {
27+
logger(`Error retrieving client from client id: [${clientId}]. ${error})`)
28+
throw error
29+
}
30+
}
31+
32+
export const clientExists = async (clientId: string): Promise<boolean> => {
33+
const { data, error } = await supabaseAdmin
34+
.from('oauth2_clients')
35+
.select('*')
36+
.eq('client_id', clientId)
37+
.single()
38+
if (error) {
39+
logger(`Unable to determine whether client exists. clientId: [${clientId}]. ${error}`)
40+
return false
41+
}
42+
return !!data
43+
}
44+
45+
export const clientHasGrantType = async (
46+
clientId: string,
47+
grantType: GrantIdentifier
48+
): Promise<boolean> => {
49+
const clientGrants: GrantIdentifier[] = await getClientGrants(clientId)
50+
return clientGrants.includes(grantType)
51+
}
52+
53+
export const getClientGrants = async (clientId: string): Promise<GrantIdentifier[]> => {
54+
const { data, error } = await supabaseAdmin
55+
.from('oauth2_client_authorization_grant_types')
56+
.select('grant_type')
57+
.eq('client_id', clientId)
58+
if (error) {
59+
logger(error)
60+
throw error
61+
}
62+
return data.map((grant) => grant.grant_type) as GrantIdentifier[]
63+
}
64+
65+
export const getClientScopes = async (clientId: string): Promise<OAuthScope[]> => {
66+
const { data, error } = await supabaseAdmin
67+
.from('oauth2_client_scopes')
68+
.select('name')
69+
.eq('client_id', clientId)
70+
if (error) {
71+
logger(error)
72+
return []
73+
}
74+
return data
75+
}

0 commit comments

Comments
 (0)