client.ts (1335B)
1 import { isSafeEqual, nonceUUID } from "#core/domain/crypto.ts"; 2 import { InvalidOAuth2Flow, OAuth2Flow } from "#core/domain/oauth2flow.ts"; 3 import { Scope } from "#core/domain/scope.ts"; 4 import { Token } from "#core/domain/token.ts"; 5 import { UUID } from "#core/domain/uuid.ts"; 6 7 export class Client { 8 constructor( 9 readonly id: UUID, 10 readonly secret: Token, 11 readonly redirectUri: URL, 12 readonly scope: Scope, 13 readonly description: string, 14 ) {} 15 16 inititate(scope: string | null = null, state: string | null = null) { 17 return new OAuth2Flow( 18 nonceUUID(), 19 this.id, 20 this.scope.intersect(Scope.of(scope)), 21 state, 22 ); 23 } 24 25 authorize(flow: OAuth2Flow, resourceOwner: UUID) { 26 if (!isSafeEqual(this.id, flow.clientId)) { 27 throw new InvalidOAuth2Flow(); 28 } 29 const code = flow.authorize(resourceOwner); 30 const url = new URL(this.redirectUri); 31 url.searchParams.set("code", code.toString()); 32 if (flow.state) { 33 url.searchParams.set("state", flow.state); 34 } 35 return url; 36 } 37 38 accessToken( 39 flow: OAuth2Flow, 40 secret: string, 41 code: string, 42 ) { 43 if ( 44 !isSafeEqual(this.id, flow.clientId) || 45 !isSafeEqual(this.secret, secret) 46 ) { 47 throw new InvalidOAuth2Flow(); 48 } 49 return flow.accessToken(new Token(code)); 50 } 51 }