Skip to content

Commit 9de4229

Browse files
committed
separate Session#fedCM method
1 parent 5a0cd00 commit 9de4229

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

src/core/AuthorizationCodeGrant.ts

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,43 @@ const buildRedirectUrl = (code, state, providerUrl) => {
99
return `${base}?code=${code}&state=${state}&iss=${encodeURIComponent(providerUrl)}`;
1010
};
1111

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+
// XXX: we ♥️ trailing slash errors
41+
// @ts-ignore
42+
const fedCMissuer = new URL(credential.configURL).origin + '/'
43+
44+
// XXX: figure out how to deal with state!!!
45+
// @ts-ignore
46+
return buildRedirectUrl(credential.token, csrf_token, fedCMissuer)
47+
}
48+
1249
/**
1350
* Login with the idp, using a provided `client_id` or dynamic client registration if none provided.
1451
*
@@ -95,30 +132,7 @@ const redirectForLogin = async (idp: string, redirect_uri: string, client_detail
95132
`&state=${csrf_token}` +
96133
`&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)
97134

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)
135+
window.location.href = redirect_to_idp;
122136
};
123137

124138
/**
@@ -331,4 +345,4 @@ const requestAccessToken = async (
331345
});
332346
};
333347

334-
export { redirectForLogin, onIncomingRedirect };
348+
export { redirectForLogin, fedCMLogin, onIncomingRedirect };

src/core/Session.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { SignJWT, decodeJwt, exportJWK } from "jose";
2-
import { redirectForLogin, onIncomingRedirect } from "./AuthorizationCodeGrant";
2+
import { redirectForLogin, fedCMLogin, onIncomingRedirect } from "./AuthorizationCodeGrant";
33
import { renewTokens } from "./RefreshTokenGrant";
44
import { SessionDatabase } from "./SessionDatabase";
55
import { DynamicRegistrationClientDetails, DereferencableIdClientDetails, SessionInformation, TokenDetails } from "./SessionInformation";
@@ -113,7 +113,12 @@ export class SessionCore extends EventTarget implements Session {
113113
}
114114

115115
async login(idp: string, redirect_uri: string) {
116-
const fedCMFakeUrl = await redirectForLogin(idp, redirect_uri, this.information.clientDetails)
116+
await redirectForLogin(idp, redirect_uri, this.information.clientDetails)
117+
}
118+
119+
async fedCM() {
120+
if (!this.information.clientDetails.client_id) throw new Error('FedCM requires Client ID URL')
121+
const fedCMFakeUrl = await fedCMLogin(this.information.clientDetails.client_id)
117122
await this.handleRedirectFromLogin(fedCMFakeUrl)
118123
}
119124

0 commit comments

Comments
 (0)