mirror of
https://github.com/juanfont/headscale.git
synced 2025-04-04 11:50:38 -04:00
OIDC: Fetch UserInfo to get EmailVerified if necessary (#2493)
This commit is contained in:
parent
badbb68217
commit
b5953d689c
@ -83,6 +83,10 @@ The new policy can be used by setting the environment variable
|
||||
- It is now possible to inspect running goroutines and take profiles
|
||||
- View of config, policy, filter, ssh policy per node, connected nodes and
|
||||
DERPmap
|
||||
- OIDC: Fetch UserInfo to get EmailVerified if necessary
|
||||
[#2493](https://github.com/juanfont/headscale/pull/2493)
|
||||
- If a OIDC provider doesn't include the `email_verified` claim in its ID
|
||||
tokens, Headscale will attempt to get it from the UserInfo endpoint.
|
||||
|
||||
## 0.25.1 (2025-02-25)
|
||||
|
||||
|
@ -234,7 +234,14 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
|
||||
return
|
||||
}
|
||||
|
||||
idToken, err := a.extractIDToken(req.Context(), code, state)
|
||||
oauth2Token, err := a.getOauth2Token(req.Context(), code, state)
|
||||
|
||||
if err != nil {
|
||||
httpError(writer, err)
|
||||
return
|
||||
}
|
||||
|
||||
idToken, err := a.extractIDToken(req.Context(), oauth2Token)
|
||||
if err != nil {
|
||||
httpError(writer, err)
|
||||
return
|
||||
@ -273,6 +280,16 @@ func (a *AuthProviderOIDC) OIDCCallbackHandler(
|
||||
return
|
||||
}
|
||||
|
||||
// If EmailVerified is missing, we can try to get it from UserInfo
|
||||
if !claims.EmailVerified {
|
||||
var userinfo *oidc.UserInfo
|
||||
userinfo, err = a.oidcProvider.UserInfo(req.Context(), oauth2.StaticTokenSource(oauth2Token))
|
||||
if err != nil {
|
||||
util.LogErr(err, "could not get userinfo; email cannot be verified")
|
||||
}
|
||||
claims.EmailVerified = types.FlexibleBoolean(userinfo.EmailVerified)
|
||||
}
|
||||
|
||||
user, err := a.createOrUpdateUserFromClaim(&claims)
|
||||
if err != nil {
|
||||
httpError(writer, err)
|
||||
@ -333,13 +350,12 @@ func extractCodeAndStateParamFromRequest(
|
||||
return code, state, nil
|
||||
}
|
||||
|
||||
// extractIDToken takes the code parameter from the callback
|
||||
// and extracts the ID token from the oauth2 token.
|
||||
func (a *AuthProviderOIDC) extractIDToken(
|
||||
// getOauth2Token exchanges the code from the callback for an oauth2 token.
|
||||
func (a *AuthProviderOIDC) getOauth2Token(
|
||||
ctx context.Context,
|
||||
code string,
|
||||
state string,
|
||||
) (*oidc.IDToken, error) {
|
||||
) (*oauth2.Token, error) {
|
||||
var exchangeOpts []oauth2.AuthCodeOption
|
||||
|
||||
if a.cfg.PKCE.Enabled {
|
||||
@ -356,7 +372,14 @@ func (a *AuthProviderOIDC) extractIDToken(
|
||||
if err != nil {
|
||||
return nil, NewHTTPError(http.StatusForbidden, "invalid code", fmt.Errorf("could not exchange code for token: %w", err))
|
||||
}
|
||||
return oauth2Token, err
|
||||
}
|
||||
|
||||
// extractIDToken extracts the ID token from the oauth2 token.
|
||||
func (a *AuthProviderOIDC) extractIDToken(
|
||||
ctx context.Context,
|
||||
oauth2Token *oauth2.Token,
|
||||
) (*oidc.IDToken, error) {
|
||||
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
return nil, NewHTTPError(http.StatusBadRequest, "no id_token", errNoOIDCIDToken)
|
||||
|
Loading…
x
Reference in New Issue
Block a user