@@ -84,27 +84,6 @@ func New(cfg Config, db *sql.DB, cb *Callbacks, lo *log.Logger) (*Auth, error) {
8484 apiUsers : map [string ]User {},
8585 }
8686
87- // Initialize OIDC.
88- if cfg .OIDC .Enabled {
89- provider , err := oidc .NewProvider (context .Background (), cfg .OIDC .ProviderURL )
90- if err != nil {
91- cfg .OIDC .Enabled = false
92- lo .Printf ("error initializing OIDC OAuth provider: %v" , err )
93- } else {
94- a .verifier = provider .Verifier (& oidc.Config {
95- ClientID : cfg .OIDC .ClientID ,
96- })
97-
98- a .oauthCfg = oauth2.Config {
99- ClientID : cfg .OIDC .ClientID ,
100- ClientSecret : cfg .OIDC .ClientSecret ,
101- Endpoint : provider .Endpoint (),
102- RedirectURL : cfg .OIDC .RedirectURL ,
103- Scopes : []string {oidc .ScopeOpenID , "profile" , "email" },
104- }
105- a .provider = provider
106- }
107- }
10887
10988 // Initialize session manager.
11089 a .sess = simplesessions .New (simplesessions.Options {
@@ -167,15 +146,91 @@ func (o *Auth) GetAPIToken(user string, token string) (User, bool) {
167146 return t , true
168147}
169148
149+ // initOIDC initializes the OIDC provider, verifier, and OAuth config.
150+ func (o * Auth ) initOIDC () error {
151+ if ! o .cfg .OIDC .Enabled {
152+ return fmt .Errorf ("OIDC is not enabled" )
153+ }
154+
155+ provider , err := oidc .NewProvider (context .Background (), o .cfg .OIDC .ProviderURL )
156+ if err != nil {
157+ return fmt .Errorf ("error initializing OIDC OAuth provider: %v" , err )
158+ }
159+
160+ o .verifier = provider .Verifier (& oidc.Config {
161+ ClientID : o .cfg .OIDC .ClientID ,
162+ })
163+
164+ o .oauthCfg = oauth2.Config {
165+ ClientID : o .cfg .OIDC .ClientID ,
166+ ClientSecret : o .cfg .OIDC .ClientSecret ,
167+ Endpoint : provider .Endpoint (),
168+ RedirectURL : o .cfg .OIDC .RedirectURL ,
169+ Scopes : []string {oidc .ScopeOpenID , "profile" , "email" },
170+ }
171+ o .provider = provider
172+
173+ return nil
174+ }
175+
176+ // getProvider returns the OIDC provider, initializing it if necessary.
177+ func (o * Auth ) getProvider () (* oidc.Provider , error ) {
178+ o .Lock ()
179+ defer o .Unlock ()
180+
181+ if o .provider == nil {
182+ if err := o .initOIDC (); err != nil {
183+ return nil , err
184+ }
185+ }
186+ return o .provider , nil
187+ }
188+
189+ // getVerifier returns the OIDC verifier, initializing it if necessary.
190+ func (o * Auth ) getVerifier () (* oidc.IDTokenVerifier , error ) {
191+ o .Lock ()
192+ defer o .Unlock ()
193+
194+ if o .verifier == nil {
195+ if err := o .initOIDC (); err != nil {
196+ return nil , err
197+ }
198+ }
199+ return o .verifier , nil
200+ }
201+
202+ // getOAuthConfig returns the OAuth config, initializing it if necessary.
203+ func (o * Auth ) getOAuthConfig () (* oauth2.Config , error ) {
204+ o .Lock ()
205+ defer o .Unlock ()
206+
207+ if o .oauthCfg .ClientID == "" {
208+ if err := o .initOIDC (); err != nil {
209+ return nil , err
210+ }
211+ }
212+ return & o .oauthCfg , nil
213+ }
214+
170215// GetOIDCAuthURL returns the OIDC provider's auth URL to redirect to.
171216func (o * Auth ) GetOIDCAuthURL (state , nonce string ) string {
172- return o .oauthCfg .AuthCodeURL (state , oidc .Nonce (nonce ))
217+ cfg , err := o .getOAuthConfig ()
218+ if err != nil {
219+ o .log .Printf ("error getting OAuth config: %v" , err )
220+ return ""
221+ }
222+ return cfg .AuthCodeURL (state , oidc .Nonce (nonce ))
173223}
174224
175225// ExchangeOIDCToken takes an OIDC authorization code (recieved via redirect from the OIDC provider),
176226// validates it, and returns an OIDC token for subsequent auth.
177227func (o * Auth ) ExchangeOIDCToken (code , nonce string ) (string , OIDCclaim , error ) {
178- tk , err := o .oauthCfg .Exchange (context .TODO (), code )
228+ cfg , err := o .getOAuthConfig ()
229+ if err != nil {
230+ return "" , OIDCclaim {}, echo .NewHTTPError (http .StatusUnauthorized , fmt .Sprintf ("error getting OAuth config: %v" , err ))
231+ }
232+
233+ tk , err := cfg .Exchange (context .TODO (), code )
179234 if err != nil {
180235 return "" , OIDCclaim {}, echo .NewHTTPError (http .StatusUnauthorized , fmt .Sprintf ("error exchanging token: %v" , err ))
181236 }
@@ -185,7 +240,12 @@ func (o *Auth) ExchangeOIDCToken(code, nonce string) (string, OIDCclaim, error)
185240 return "" , OIDCclaim {}, echo .NewHTTPError (http .StatusUnauthorized , "`id_token` missing." )
186241 }
187242
188- idTk , err := o .verifier .Verify (context .TODO (), rawIDTk )
243+ verifier , err := o .getVerifier ()
244+ if err != nil {
245+ return "" , OIDCclaim {}, echo .NewHTTPError (http .StatusUnauthorized , fmt .Sprintf ("error getting verifier: %v" , err ))
246+ }
247+
248+ idTk , err := verifier .Verify (context .TODO (), rawIDTk )
189249 if err != nil {
190250 return "" , OIDCclaim {}, echo .NewHTTPError (http .StatusUnauthorized , fmt .Sprintf ("error verifying ID token: %v" , err ))
191251 }
@@ -201,7 +261,12 @@ func (o *Auth) ExchangeOIDCToken(code, nonce string) (string, OIDCclaim, error)
201261
202262 // If claims doesn't have the e-mail, attempt to fetch it from the userinfo endpoint.
203263 if claims .Email == "" {
204- userInfo , err := o .provider .UserInfo (context .TODO (), oauth2 .StaticTokenSource (tk ))
264+ provider , err := o .getProvider ()
265+ if err != nil {
266+ return "" , OIDCclaim {}, fmt .Errorf ("error getting provider: %v" , err )
267+ }
268+
269+ userInfo , err := provider .UserInfo (context .TODO (), oauth2 .StaticTokenSource (tk ))
205270 if err != nil {
206271 return "" , OIDCclaim {}, errors .New ("error fetching user info from OIDC" )
207272 }
0 commit comments