@@ -9,18 +9,48 @@ const buildRedirectUrl = (code, state, providerUrl) => {
99 return `${ base } ?code=${ code } &state=${ state } &iss=${ encodeURIComponent ( providerUrl ) } ` ;
1010} ;
1111
12- /**
13- * Login with the idp, using a provided `client_id` or dynamic client registration if none provided.
14- *
15- * @param idp
16- * @param redirect_uri
17- */
18- const redirectForLogin = async ( idp : string , redirect_uri : string , client_details ?: ClientDetails ) => {
19- // RFC 6749 - Section 3.1.2 - sanitize redirect_uri
20- const redirect_uri_ = new URL ( redirect_uri ) ;
21- const redirect_uri_sane = redirect_uri_ . origin + redirect_uri_ . pathname + redirect_uri_ . search ;
22- // lookup openid configuration of idp
23- const idp_origin = new URL ( idp ) . origin ;
12+ const fedCMLogin = async ( clientId : string ) : Promise < string > => {
13+
14+ // RFC 7636 PKCE, remember code verifer
15+ const { pkce_code_verifier, pkce_code_challenge } = await getPKCEcode ( ) ;
16+ sessionStorage . setItem ( "pkce_code_verifier" , pkce_code_verifier ) ;
17+
18+ // RFC 6749 OAuth 2.0 - CSRF token
19+ const csrf_token = window . crypto . randomUUID ( ) ;
20+ sessionStorage . setItem ( "csrf_token" , csrf_token ) ;
21+
22+ const credential = await navigator . credentials . get ( {
23+ // @ts -ignore
24+ identity : {
25+ providers : [ {
26+ configURL : 'any' ,
27+ clientId : clientId ,
28+ registered : true ,
29+ params : {
30+ code_challenge : pkce_code_challenge ,
31+ code_challenge_method : 'S256' ,
32+ state : csrf_token
33+ }
34+ } ]
35+ }
36+ } ) ;
37+
38+ console . log ( 'FedCM returned' , credential )
39+
40+ // @ts -ignore
41+ const fedCMissuer = new URL ( credential . configURL )
42+
43+ // XXX: we ♥️ trailing slash errors
44+ sessionStorage . setItem ( "idp" , fedCMissuer . origin + '/' ) ;
45+
46+ await lookupIdp ( fedCMissuer . origin + '/' , fedCMissuer . origin )
47+
48+ // XXX: figure out how to deal with state!!!
49+ // @ts -ignore
50+ return buildRedirectUrl ( credential . token , csrf_token , fedCMissuer . origin + '/' )
51+ }
52+
53+ const lookupIdp = async ( idp : string , idp_origin : string ) => {
2454 const openid_configuration =
2555 await fetch ( `${ idp_origin } /.well-known/openid-configuration` )
2656 . then ( ( response ) => {
@@ -48,6 +78,22 @@ const redirectForLogin = async (idp: string, redirect_uri: string, client_detail
4878 "jwks_uri" ,
4979 openid_configuration [ "jwks_uri" ]
5080 ) ;
81+ return openid_configuration
82+ }
83+
84+ /**
85+ * Login with the idp, using a provided `client_id` or dynamic client registration if none provided.
86+ *
87+ * @param idp
88+ * @param redirect_uri
89+ */
90+ const redirectForLogin = async ( idp : string , redirect_uri : string , client_details ?: ClientDetails ) => {
91+ // RFC 6749 - Section 3.1.2 - sanitize redirect_uri
92+ const redirect_uri_ = new URL ( redirect_uri ) ;
93+ const redirect_uri_sane = redirect_uri_ . origin + redirect_uri_ . pathname + redirect_uri_ . search ;
94+ // lookup openid configuration of idp
95+ const idp_origin = new URL ( idp ) . origin ;
96+ const openid_configuration = await lookupIdp ( idp , idp_origin )
5197
5298 let client_id = client_details ?. client_id ;
5399 // no client_id => attempt dynamic registration
@@ -95,30 +141,7 @@ const redirectForLogin = async (idp: string, redirect_uri: string, client_detail
95141 `&state=${ csrf_token } ` +
96142 `&prompt=consent` ; // this query parameter value MUST be present for CSS v7 to issue a refresh token ( // TODO open issue because prompting is the default behaviour but without this query param no refresh token is provided despite the "remember this client" box being checked)
97143
98- // do FedCM dance 💃🏻
99- // do check first!
100- const params = Object . fromEntries ( new URL ( redirect_to_idp ) . searchParams ) ;
101- const credential = await navigator . credentials . get ( {
102- // @ts -ignore
103- identity : {
104- providers : [ {
105- configURL : 'any' ,
106- clientId : params . client_id ,
107- registered : true ,
108- params : {
109- code_challenge : params . code_challenge ,
110- code_challenge_method : params . code_challenge_method ,
111- state : params . state
112- }
113- } ]
114- }
115- } ) ;
116- console . log ( credential )
117- // XXX: we ♥️ trailing slash errors
118- // @ts -ignore
119- const fedCMissuer = new URL ( credential . configURL ) . origin + '/'
120- // @ts -ignore
121- return buildRedirectUrl ( credential . token , params . state , fedCMissuer )
144+ window . location . href = redirect_to_idp ;
122145} ;
123146
124147/**
@@ -331,4 +354,4 @@ const requestAccessToken = async (
331354 } ) ;
332355} ;
333356
334- export { redirectForLogin , onIncomingRedirect } ;
357+ export { redirectForLogin , fedCMLogin , onIncomingRedirect } ;
0 commit comments