55 * of the MIT license. See the LICENSE file for details.
66 */
77import { CustomLogger , logger as loggerFn , LogLevel } from '@forgerock/sdk-logger' ;
8- import { createAuthorizeUrl } from '@forgerock/sdk-oidc' ;
8+ import { createAuthorizeUrl , getStoredAuthUrlValues } from '@forgerock/sdk-oidc' ;
9+ import { createStorage } from '@forgerock/storage' ;
10+ import { Micro } from 'effect' ;
911import { exitIsSuccess } from 'effect/Micro' ;
1012
1113import { authorizeµ } from './authorize.request.js' ;
1214import { createClientStore } from './client.store.utils.js' ;
1315import { GenericError } from './error.types.js' ;
16+ import { oidcApi } from './oidc.api.js' ;
1417import { wellknownApi , wellknownSelector } from './wellknown.api.js' ;
1518
1619import type { ActionTypes , RequestMiddleware } from '@forgerock/sdk-request-middleware' ;
1720import type { GetAuthorizationUrlOptions } from '@forgerock/sdk-types' ;
1821
1922import type { OidcConfig } from './config.types.js' ;
20- import { Micro } from 'effect' ;
23+ import { AuthorizeErrorResponse } from './authorize.request.types.js' ;
24+ import { TokenExchangeOptions } from './client.store.types.js' ;
25+ import { TokenRequestOptions } from './token.types.js' ;
2126
2227export async function oidc < ActionType extends ActionTypes = ActionTypes > ( {
2328 config,
@@ -36,13 +41,13 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
3641
3742 if ( ! config ?. serverConfig ?. wellknown ) {
3843 return {
39- message : 'Requires a wellknown url initializing this factory.' ,
44+ error : 'Requires a wellknown url initializing this factory.' ,
4045 type : 'argument_error' ,
4146 } ;
4247 }
4348 if ( ! config ?. clientId ) {
4449 return {
45- message : 'Requires a clientId.' ,
50+ error : 'Requires a clientId.' ,
4651 type : 'argument_error' ,
4752 } ;
4853 }
@@ -54,7 +59,7 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
5459
5560 if ( error || ! data ) {
5661 return {
57- message : `Error fetching wellknown config` ,
62+ error : `Error fetching wellknown config` ,
5863 type : 'network_error' ,
5964 } ;
6065 }
@@ -75,11 +80,11 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
7580
7681 if ( ! wellknown ?. authorization_endpoint ) {
7782 const err = {
78- message : 'Authorization endpoint not found in wellknown configuration' ,
83+ error : 'Authorization endpoint not found in wellknown configuration' ,
7984 type : 'wellknown_error' ,
8085 } as const ;
8186
82- log . error ( err . message ) ;
87+ log . error ( err . error ) ;
8388
8489 return err ;
8590 }
@@ -92,11 +97,12 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
9297
9398 if ( ! wellknown ?. authorization_endpoint ) {
9499 const err = {
95- message : 'Authorization endpoint not found in wellknown configuration' ,
100+ error : 'Wellknown missing authorization endpoint' ,
101+ error_description : 'Authorization endpoint not found in wellknown configuration' ,
96102 type : 'wellknown_error' ,
97- } as const ;
103+ } as AuthorizeErrorResponse ;
98104
99- log . error ( err . message ) ;
105+ log . error ( err . error ) ;
100106
101107 return err ;
102108 }
@@ -108,9 +114,75 @@ export async function oidc<ActionType extends ActionTypes = ActionTypes>({
108114 if ( exitIsSuccess ( result ) ) {
109115 return result . value ;
110116 } else {
111- return result . cause ;
117+ return {
118+ error : 'Authorization failure' ,
119+ error_description : result . cause . message ,
120+ type : 'auth_error' ,
121+ } as AuthorizeErrorResponse ;
112122 }
113123 } ,
114124 } ,
125+ token : {
126+ exchange : async ( code : string , state : string , options ?: TokenExchangeOptions ) => {
127+ const storeState = store . getState ( ) ;
128+ const wellknown = wellknownSelector ( wellknownUrl , storeState ) ;
129+
130+ if ( ! wellknown ?. token_endpoint ) {
131+ const err = {
132+ error : 'Wellknown missing token endpoint' ,
133+ type : 'wellknown_error' ,
134+ } as AuthorizeErrorResponse ;
135+
136+ log . error ( err . error ) ;
137+
138+ return err ;
139+ }
140+
141+ // TODO: Validate state
142+ const values = getStoredAuthUrlValues ( config . clientId , options ?. prefix ) ;
143+
144+ if ( values . state !== state ) {
145+ const err = {
146+ error : 'State mismatch' ,
147+ type : 'auth_error' ,
148+ } as GenericError ;
149+
150+ log . error ( err . error ) ;
151+
152+ return err ;
153+ }
154+
155+ const requestOptions : TokenRequestOptions = {
156+ code,
157+ config,
158+ endpoint : wellknown . token_endpoint ,
159+ } ;
160+ if ( values . verifier ) {
161+ requestOptions . verifier = values . verifier ;
162+ }
163+
164+ const { data, error } = await store . dispatch (
165+ oidcApi . endpoints . exchange . initiate ( requestOptions ) ,
166+ ) ;
167+
168+ if ( error || ! data ) {
169+ const err = {
170+ error : 'Error exchanging token' ,
171+ type : 'network_error' ,
172+ } as GenericError ;
173+
174+ log . error ( err . error ) ;
175+
176+ return err ;
177+ }
178+
179+ // TODO: handle response and errors; if success, store tokens and return them
180+ createStorage ( { storeType : 'localStorage' } , 'oidcTokens' , options ?. customStorage ) . set (
181+ data ,
182+ ) ;
183+
184+ return data ;
185+ } ,
186+ } ,
115187 } ;
116188}
0 commit comments