11import { later } from "@ember/runloop" ;
22import { inject as service } from "@ember/service" ;
3+ import { camelize } from "@ember/string" ;
4+ import { lastValue , task } from "ember-concurrency" ;
35import BaseAuthenticator from "ember-simple-auth/authenticators/base" ;
46import { resolve } from "rsvp" ;
57import { TrackedObject } from "tracked-built-ins" ;
@@ -12,12 +14,47 @@ import {
1214 isBadRequestResponse ,
1315} from "ember-simple-auth-oidc/utils/errors" ;
1416
17+ const camelizeObjectKeys = ( obj ) => {
18+ Object . keys ( obj ) . forEach ( ( key ) => {
19+ obj [ camelize ( key ) ] = obj [ key ] ;
20+ delete obj [ key ] ;
21+ } ) ;
22+ return obj ;
23+ } ;
24+
1525export default class OidcAuthenticator extends BaseAuthenticator {
1626 @service router ;
1727 @service session ;
1828
1929 @config config ;
2030
31+ get configuration ( ) {
32+ return { ...this . config , ...this . fetchedConfig } ;
33+ }
34+
35+ get hasEndpointsConfigured ( ) {
36+ return (
37+ this . configuration . tokenEndpoint && this . configuration . userinfoEndpoint
38+ ) ;
39+ }
40+
41+ /**
42+ * Tries to fetch the OIDC provider configuration from the specified host/realm.
43+ * SPEC: https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig
44+ */
45+ @lastValue ( "_fetchAuthConfiguration" ) fetchedConfig ;
46+ _fetchAuthConfiguration = task ( async ( ) => {
47+ if ( ! this . config . host ) {
48+ throw new Error ( "Please define a OIDC host." ) ;
49+ }
50+ const response = await fetch (
51+ `${ this . config . host } /.well-known/openid-configuration` ,
52+ ) ;
53+ const json = await response . json ( ) ;
54+
55+ return camelizeObjectKeys ( json . data ) ;
56+ } ) ;
57+
2158 /**
2259 * Authenticate the client with the given authentication code. The
2360 * authentication call will return an access and refresh token which will
@@ -28,10 +65,14 @@ export default class OidcAuthenticator extends BaseAuthenticator {
2865 * @returns {Object } The parsed response data
2966 */
3067 async authenticate ( { code, redirectUri, codeVerifier, isRefresh } ) {
31- if ( ! this . config . tokenEndpoint || ! this . config . userinfoEndpoint ) {
32- throw new Error (
33- "Please define all OIDC endpoints (auth, token, userinfo)" ,
34- ) ;
68+ if ( ! this . hasEndpointsConfigured ) {
69+ await this . _fetchAuthConfiguration . perform ( ) ;
70+
71+ if ( ! this . hasEndpointsConfigured ) {
72+ throw new Error (
73+ "Please define all OIDC endpoints (auth, token, userinfo)" ,
74+ ) ;
75+ }
3576 }
3677
3778 if ( isRefresh ) {
@@ -43,12 +84,12 @@ export default class OidcAuthenticator extends BaseAuthenticator {
4384
4485 const bodyObject = {
4586 code,
46- client_id : this . config . clientId ,
87+ client_id : this . configuration . clientId ,
4788 grant_type : "authorization_code" ,
4889 redirect_uri : redirectUri ,
4990 } ;
5091
51- if ( this . config . enablePkce ) {
92+ if ( this . configuration . enablePkce ) {
5293 bodyObject . code_verifier = codeVerifier ;
5394 }
5495
@@ -57,7 +98,7 @@ export default class OidcAuthenticator extends BaseAuthenticator {
5798 . join ( "&" ) ;
5899
59100 const response = await fetch (
60- getAbsoluteUrl ( this . config . tokenEndpoint , this . config . host ) ,
101+ getAbsoluteUrl ( this . configuration . tokenEndpoint , this . config . host ) ,
61102 {
62103 method : "POST" ,
63104 headers : {
@@ -101,16 +142,16 @@ export default class OidcAuthenticator extends BaseAuthenticator {
101142 * @param {String } idToken The id_token of the session to invalidate
102143 */
103144 singleLogout ( idToken ) {
104- if ( ! this . config . endSessionEndpoint ) {
145+ if ( ! this . configuration . endSessionEndpoint ) {
105146 return ;
106147 }
107148
108149 const params = [ ] ;
109150
110- if ( this . config . afterLogoutUri ) {
151+ if ( this . configuration . afterLogoutUri ) {
111152 params . push (
112153 `post_logout_redirect_uri=${ getAbsoluteUrl (
113- this . config . afterLogoutUri ,
154+ this . configuration . afterLogoutUri ,
114155 ) } `,
115156 ) ;
116157 }
@@ -121,8 +162,8 @@ export default class OidcAuthenticator extends BaseAuthenticator {
121162
122163 this . _redirectToUrl (
123164 `${ getAbsoluteUrl (
124- this . config . endSessionEndpoint ,
125- this . config . host ,
165+ this . configuration . endSessionEndpoint ,
166+ this . configuration . host ,
126167 ) } ?${ params . join ( "&" ) } `,
127168 ) ;
128169 }
@@ -167,7 +208,7 @@ export default class OidcAuthenticator extends BaseAuthenticator {
167208 try {
168209 const bodyObject = {
169210 refresh_token,
170- client_id : this . config . clientId ,
211+ client_id : this . configuration . clientId ,
171212 grant_type : "refresh_token" ,
172213 redirect_uri : redirectUri ,
173214 } ;
@@ -176,7 +217,7 @@ export default class OidcAuthenticator extends BaseAuthenticator {
176217 . join ( "&" ) ;
177218
178219 const response = await fetch (
179- getAbsoluteUrl ( this . config . tokenEndpoint , this . config . host ) ,
220+ getAbsoluteUrl ( this . configuration . tokenEndpoint , this . config . host ) ,
180221 {
181222 method : "POST" ,
182223 headers : {
@@ -202,7 +243,7 @@ export default class OidcAuthenticator extends BaseAuthenticator {
202243 } catch ( e ) {
203244 if (
204245 ( isServerError || isAbortError ( e ) ) &&
205- retryCount < this . config . amountOfRetries - 1
246+ retryCount < this . configuration . amountOfRetries - 1
206247 ) {
207248 return new Promise ( ( resolve ) => {
208249 later (
@@ -211,7 +252,7 @@ export default class OidcAuthenticator extends BaseAuthenticator {
211252 resolve (
212253 this . _refresh ( refresh_token , redirectUri , retryCount + 1 ) ,
213254 ) ,
214- this . config . retryTimeout ,
255+ this . configuration . retryTimeout ,
215256 ) ;
216257 } ) ;
217258 }
@@ -227,10 +268,10 @@ export default class OidcAuthenticator extends BaseAuthenticator {
227268 */
228269 async _getUserinfo ( accessToken ) {
229270 const response = await fetch (
230- getAbsoluteUrl ( this . config . userinfoEndpoint , this . config . host ) ,
271+ getAbsoluteUrl ( this . configuration . userinfoEndpoint , this . config . host ) ,
231272 {
232273 headers : {
233- Authorization : `${ this . config . authPrefix } ${ accessToken } ` ,
274+ Authorization : `${ this . configuration . authPrefix } ${ accessToken } ` ,
234275 Accept : "application/json" ,
235276 } ,
236277 } ,
@@ -262,9 +303,11 @@ export default class OidcAuthenticator extends BaseAuthenticator {
262303
263304 const expireInMilliseconds = expires_in
264305 ? expires_in * 1000
265- : this . config . expiresIn ;
306+ : this . configuration . expiresIn ;
266307 const expireTime =
267- new Date ( ) . getTime ( ) + expireInMilliseconds - this . config . refreshLeeway ;
308+ new Date ( ) . getTime ( ) +
309+ expireInMilliseconds -
310+ this . configuration . refreshLeeway ;
268311
269312 return new TrackedObject ( {
270313 access_token,
0 commit comments