@@ -157,6 +157,17 @@ export type RoutesOptions = Partial<
157157 >
158158> ;
159159
160+ // We are using an internal method of DPoPHandle.
161+ // We should look for a way to achieve this without relying on internal methods.
162+ type DPoPHandle = oauth . DPoPHandle & {
163+ addProof : (
164+ url : URL ,
165+ headers : Headers ,
166+ htm : string ,
167+ accessToken ?: string
168+ ) => Promise < void > ;
169+ } ;
170+
160171export interface AuthClientOptions {
161172 transactionStore : TransactionStore ;
162173 sessionStore : AbstractSessionStore ;
@@ -399,6 +410,10 @@ export class AuthClient {
399410 this . enableConnectAccountEndpoint
400411 ) {
401412 return this . handleConnectAccount ( req ) ;
413+ } else if ( sanitizedPathname . startsWith ( "/me" ) ) {
414+ return this . handleMyAccount ( req ) ;
415+ } else if ( sanitizedPathname . startsWith ( "/my-org" ) ) {
416+ return this . handleMyOrg ( req ) ;
402417 } else {
403418 // no auth handler found, simply touch the sessions
404419 // TODO: this should only happen if rolling sessions are enabled. Also, we should
@@ -1073,6 +1088,75 @@ export class AuthClient {
10731088 return connectAccountResponse ;
10741089 }
10751090
1091+ async handleMyAccount ( req : NextRequest ) : Promise < NextResponse > {
1092+ return this . handleProxy ( req , {
1093+ proxyPath : "/me" ,
1094+ targetBaseUrl : `${ this . issuer } /me/v1` ,
1095+ audience : `${ this . issuer } /me/v1/`
1096+ } ) ;
1097+ }
1098+
1099+ async handleMyOrg ( req : NextRequest ) : Promise < NextResponse > {
1100+ return this . handleProxy ( req , {
1101+ proxyPath : "/my-org" ,
1102+ targetBaseUrl : `${ this . issuer } /my-org` ,
1103+ audience : `${ this . issuer } /my-org/`
1104+ } ) ;
1105+ }
1106+
1107+ async handleProxy (
1108+ req : NextRequest ,
1109+ options : {
1110+ proxyPath : string ;
1111+ targetBaseUrl : string ;
1112+ audience : string ;
1113+ }
1114+ ) : Promise < NextResponse > {
1115+ const session = await this . sessionStore . get ( req . cookies ) ;
1116+ if ( ! session ) {
1117+ return new NextResponse ( "The user does not have an active session." , {
1118+ status : 401
1119+ } ) ;
1120+ }
1121+
1122+ const targetBaseUrl = options . targetBaseUrl ;
1123+ const targetUrl = new URL (
1124+ req . nextUrl . pathname . replace ( options . proxyPath , targetBaseUrl . toString ( ) )
1125+ ) ;
1126+
1127+ const [ error , token ] = await this . getTokenSet ( session , {
1128+ audience : targetBaseUrl . toString ( ) ,
1129+ scope : req . headers . get ( "auth0-scope" )
1130+ } ) ;
1131+
1132+ if ( error ) {
1133+ throw new Error (
1134+ `Failed to retrieve access token for My Account: ${ error . message } `
1135+ ) ;
1136+ }
1137+
1138+ const headers = new Headers ( req . headers ) ;
1139+
1140+ if ( token . tokenSet . token_type ?. toLowerCase ( ) === "bearer" ) {
1141+ headers . set ( "Authorization" , `Bearer ${ token . tokenSet . accessToken } ` ) ;
1142+ } else {
1143+ const dpopHandle = oauth . DPoP (
1144+ this . clientMetadata ,
1145+ this . dpopKeyPair !
1146+ ) as DPoPHandle ;
1147+
1148+ // TODO: This is a private method on oauth4webapi.
1149+ // We probably should not use this but replace with a different way to add the proof.
1150+ dpopHandle . addProof ( targetUrl , headers , req . method ) ;
1151+
1152+ headers . set ( "Authorization" , `DPoP ${ token ?. tokenSet . accessToken } ` ) ;
1153+ }
1154+
1155+ return NextResponse . rewrite ( targetUrl , {
1156+ request : { headers }
1157+ } ) ;
1158+ }
1159+
10761160 /**
10771161 * Retrieves the token set from the session data, considering optional audience and scope parameters.
10781162 * When audience and scope are provided, it checks if they match the global ones defined in the authorization parameters.
0 commit comments