mirror of
https://github.com/netbirdio/netbird.git
synced 2025-06-18 15:56:41 +02:00
Update scripts for the self-hosted Oauth 2.0 Device Auth Grant support (#439)
Support Oauth 2.0 Device Auth Grant in the self-hosted scripts.
This commit is contained in:
parent
3def84b111
commit
e8733a37af
23
.github/workflows/test-docker-compose-linux.yml
vendored
23
.github/workflows/test-docker-compose-linux.yml
vendored
@ -5,6 +5,12 @@ jobs:
|
|||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Install jq
|
||||||
|
run: sudo apt-get install -y jq
|
||||||
|
|
||||||
|
- name: Install curl
|
||||||
|
run: sudo apt-get install -y curl
|
||||||
|
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
@ -28,30 +34,31 @@ jobs:
|
|||||||
working-directory: infrastructure_files
|
working-directory: infrastructure_files
|
||||||
run: bash -x configure.sh
|
run: bash -x configure.sh
|
||||||
env:
|
env:
|
||||||
CI_NETBIRD_AUTH_AUTHORITY: ${{ secrets.CI_NETBIRD_AUTH_AUTHORITY }}
|
|
||||||
CI_NETBIRD_AUTH_CLIENT_ID: ${{ secrets.CI_NETBIRD_AUTH_CLIENT_ID }}
|
CI_NETBIRD_AUTH_CLIENT_ID: ${{ secrets.CI_NETBIRD_AUTH_CLIENT_ID }}
|
||||||
CI_NETBIRD_AUTH_AUDIENCE: testing.ci
|
CI_NETBIRD_AUTH_AUDIENCE: testing.ci
|
||||||
CI_NETBIRD_AUTH_JWT_CERTS: ${{ secrets.CI_NETBIRD_AUTH_AUTHORITY }}.well-known/jwks.json
|
CI_NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT: https://example.eu.auth0.com/.well-known/openid-configuration
|
||||||
CI_NETBIRD_AUTH_SUPPORTED_SCOPES: openid
|
|
||||||
CI_NETBIRD_USE_AUTH0: true
|
CI_NETBIRD_USE_AUTH0: true
|
||||||
|
|
||||||
- name: check values
|
- name: check values
|
||||||
working-directory: infrastructure_files
|
working-directory: infrastructure_files
|
||||||
env:
|
env:
|
||||||
CI_NETBIRD_AUTH_AUTHORITY: ${{ secrets.CI_NETBIRD_AUTH_AUTHORITY }}
|
|
||||||
CI_NETBIRD_AUTH_CLIENT_ID: ${{ secrets.CI_NETBIRD_AUTH_CLIENT_ID }}
|
CI_NETBIRD_AUTH_CLIENT_ID: ${{ secrets.CI_NETBIRD_AUTH_CLIENT_ID }}
|
||||||
CI_NETBIRD_AUTH_AUDIENCE: testing.ci
|
CI_NETBIRD_AUTH_AUDIENCE: testing.ci
|
||||||
CI_NETBIRD_AUTH_JWT_CERTS: ${{ secrets.CI_NETBIRD_AUTH_AUTHORITY }}.well-known/jwks.json
|
CI_NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT: https://example.eu.auth0.com/.well-known/openid-configuration
|
||||||
CI_NETBIRD_AUTH_SUPPORTED_SCOPES: openid
|
|
||||||
CI_NETBIRD_USE_AUTH0: true
|
CI_NETBIRD_USE_AUTH0: true
|
||||||
|
CI_NETBIRD_AUTH_SUPPORTED_SCOPES: "openid profile email offline_access api email_verified"
|
||||||
|
CI_NETBIRD_AUTH_AUTHORITY: https://example.eu.auth0.com/
|
||||||
|
CI_NETBIRD_AUTH_JWT_CERTS: https://example.eu.auth0.com/.well-known/jwks.json
|
||||||
|
CI_NETBIRD_AUTH_TOKEN_ENDPOINT: https://example.eu.auth0.com/oauth/token
|
||||||
|
CI_NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT: https://example.eu.auth0.com/oauth/device/code
|
||||||
run: |
|
run: |
|
||||||
grep AUTH_CLIENT_ID docker-compose.yml | grep $CI_NETBIRD_AUTH_CLIENT_ID
|
grep AUTH_CLIENT_ID docker-compose.yml | grep $CI_NETBIRD_AUTH_CLIENT_ID
|
||||||
grep AUTH_AUTHORITY docker-compose.yml | grep $CI_NETBIRD_AUTH_AUTHORITY
|
grep AUTH_AUTHORITY docker-compose.yml | grep $CI_NETBIRD_AUTH_AUTHORITY
|
||||||
grep AUTH_AUDIENCE docker-compose.yml | grep $CI_NETBIRD_AUTH_AUDIENCE
|
grep AUTH_AUDIENCE docker-compose.yml | grep $CI_NETBIRD_AUTH_AUDIENCE
|
||||||
grep AUTH_SUPPORTED_SCOPES docker-compose.yml | grep $CI_NETBIRD_AUTH_SUPPORTED_SCOPES
|
grep AUTH_SUPPORTED_SCOPES docker-compose.yml | grep "$CI_NETBIRD_AUTH_SUPPORTED_SCOPES"
|
||||||
grep USE_AUTH0 docker-compose.yml | grep $CI_NETBIRD_USE_AUTH0
|
grep USE_AUTH0 docker-compose.yml | grep $CI_NETBIRD_USE_AUTH0
|
||||||
grep NETBIRD_MGMT_API_ENDPOINT docker-compose.yml | grep "http://localhost:33073"
|
grep NETBIRD_MGMT_API_ENDPOINT docker-compose.yml | grep "http://localhost:33073"
|
||||||
|
|
||||||
- name: run docker compose up
|
- name: run docker compose up
|
||||||
working-directory: infrastructure_files
|
working-directory: infrastructure_files
|
||||||
run: |
|
run: |
|
||||||
|
@ -27,6 +27,8 @@ MGMT_VOLUMESUFFIX="mgmt"
|
|||||||
SIGNAL_VOLUMESUFFIX="signal"
|
SIGNAL_VOLUMESUFFIX="signal"
|
||||||
LETSENCRYPT_VOLUMESUFFIX="letsencrypt"
|
LETSENCRYPT_VOLUMESUFFIX="letsencrypt"
|
||||||
|
|
||||||
|
NETBIRD_AUTH_DEVICE_AUTH_PROVIDER="none"
|
||||||
|
|
||||||
# exports
|
# exports
|
||||||
export NETBIRD_DOMAIN
|
export NETBIRD_DOMAIN
|
||||||
export NETBIRD_AUTH_CLIENT_ID
|
export NETBIRD_AUTH_CLIENT_ID
|
||||||
@ -40,6 +42,9 @@ export NETBIRD_MGMT_API_PORT
|
|||||||
export NETBIRD_MGMT_API_ENDPOINT
|
export NETBIRD_MGMT_API_ENDPOINT
|
||||||
export NETBIRD_MGMT_API_CERT_FILE
|
export NETBIRD_MGMT_API_CERT_FILE
|
||||||
export NETBIRD_MGMT_API_CERT_KEY_FILE
|
export NETBIRD_MGMT_API_CERT_KEY_FILE
|
||||||
|
export NETBIRD_AUTH_DEVICE_AUTH_PROVIDER
|
||||||
|
export NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID
|
||||||
|
export NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT
|
||||||
export TURN_USER
|
export TURN_USER
|
||||||
export TURN_PASSWORD
|
export TURN_PASSWORD
|
||||||
export TURN_MIN_PORT
|
export TURN_MIN_PORT
|
||||||
|
@ -1,5 +1,21 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
if ! which curl > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "This script uses curl fetch OpenID configuration from IDP."
|
||||||
|
echo "Please install curl and re-run the script https://curl.se/"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! which jq > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "This script uses jq to load OpenID configuration from IDP."
|
||||||
|
echo "Please install jq and re-run the script https://stedolan.github.io/jq/"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
source setup.env
|
source setup.env
|
||||||
source base.setup.env
|
source base.setup.env
|
||||||
|
|
||||||
@ -63,21 +79,49 @@ export MGMT_VOLUMENAME
|
|||||||
export SIGNAL_VOLUMENAME
|
export SIGNAL_VOLUMENAME
|
||||||
export LETSENCRYPT_VOLUMENAME
|
export LETSENCRYPT_VOLUMENAME
|
||||||
|
|
||||||
#backwards compatibility after migrating to generic OIDC
|
#backwards compatibility after migrating to generic OIDC with Auth0
|
||||||
if [[ -z "${NETBIRD_AUTH_AUTHORITY}" ]]; then
|
if [[ -z "${NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT}" ]]; then
|
||||||
|
|
||||||
|
if [[ -z "${NETBIRD_AUTH0_DOMAIN}" ]]; then
|
||||||
|
# not a backward compatible state
|
||||||
|
echo "NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT property must be set in the setup.env file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
echo "It seems like you provided an old setup.env file."
|
echo "It seems like you provided an old setup.env file."
|
||||||
echo "Since the release of v0.8.8, we introduced a new set of properties."
|
echo "Since the release of v0.8.10, we introduced a new set of properties."
|
||||||
echo "The script is backward compatible and will continue automatically."
|
echo "The script is backward compatible and will continue automatically."
|
||||||
echo "In the future versions it will be deprecated. Please refer to the documentation to learn about the changes http://netbird.io/docs/getting-started/self-hosting"
|
echo "In the future versions it will be deprecated. Please refer to the documentation to learn about the changes http://netbird.io/docs/getting-started/self-hosting"
|
||||||
|
|
||||||
export NETBIRD_AUTH_AUTHORITY="https://${NETBIRD_AUTH0_DOMAIN}/"
|
export NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT="https://${NETBIRD_AUTH0_DOMAIN}/.well-known/openid-configuration"
|
||||||
export NETBIRD_AUTH_CLIENT_ID=${NETBIRD_AUTH0_CLIENT_ID}
|
|
||||||
export NETBIRD_USE_AUTH0="true"
|
export NETBIRD_USE_AUTH0="true"
|
||||||
export NETBIRD_AUTH_SUPPORTED_SCOPES="openid profile email api offline_access email_verified"
|
|
||||||
export NETBIRD_AUTH_AUDIENCE=${NETBIRD_AUTH0_AUDIENCE}
|
export NETBIRD_AUTH_AUDIENCE=${NETBIRD_AUTH0_AUDIENCE}
|
||||||
export NETBIRD_AUTH_JWT_CERTS="https://${NETBIRD_AUTH0_DOMAIN}/.well-known/jwks.json"
|
export NETBIRD_AUTH_CLIENT_ID=${NETBIRD_AUTH0_CLIENT_ID}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "loading OpenID configuration from ${NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT} to the openid-configuration.json file"
|
||||||
|
curl "${NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT}" -q -o openid-configuration.json
|
||||||
|
|
||||||
|
export NETBIRD_AUTH_AUTHORITY=$( jq -r '.issuer' openid-configuration.json )
|
||||||
|
export NETBIRD_AUTH_JWT_CERTS=$( jq -r '.jwks_uri' openid-configuration.json )
|
||||||
|
export NETBIRD_AUTH_SUPPORTED_SCOPES=$( jq -r '.scopes_supported | join(" ")' openid-configuration.json )
|
||||||
|
export NETBIRD_AUTH_TOKEN_ENDPOINT=$( jq -r '.token_endpoint' openid-configuration.json )
|
||||||
|
export NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT=$( jq -r '.device_authorization_endpoint' openid-configuration.json )
|
||||||
|
|
||||||
|
if [ $NETBIRD_USE_AUTH0 == "true" ]
|
||||||
|
then
|
||||||
|
export NETBIRD_AUTH_SUPPORTED_SCOPES="openid profile email offline_access api email_verified"
|
||||||
|
else
|
||||||
|
export NETBIRD_AUTH_SUPPORTED_SCOPES="openid profile email offline_access api"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -z "${NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID}" ]]; then
|
||||||
|
# user enabled Device Authorization Grant feature
|
||||||
|
export NETBIRD_AUTH_DEVICE_AUTH_PROVIDER="hosted"
|
||||||
|
fi
|
||||||
|
|
||||||
|
env | grep NETBIRD
|
||||||
|
|
||||||
envsubst < docker-compose.yml.tmpl > docker-compose.yml
|
envsubst < docker-compose.yml.tmpl > docker-compose.yml
|
||||||
envsubst < management.json.tmpl > management.json
|
envsubst < management.json.tmpl > management.json
|
||||||
envsubst < turnserver.conf.tmpl > turnserver.conf
|
envsubst < turnserver.conf.tmpl > turnserver.conf
|
||||||
|
@ -33,9 +33,20 @@
|
|||||||
"AuthAudience": "$NETBIRD_AUTH_AUDIENCE",
|
"AuthAudience": "$NETBIRD_AUTH_AUDIENCE",
|
||||||
"AuthKeysLocation": "$NETBIRD_AUTH_JWT_CERTS",
|
"AuthKeysLocation": "$NETBIRD_AUTH_JWT_CERTS",
|
||||||
"CertFile":"$NETBIRD_MGMT_API_CERT_FILE",
|
"CertFile":"$NETBIRD_MGMT_API_CERT_FILE",
|
||||||
"CertKey":"$NETBIRD_MGMT_API_CERT_KEY_FILE"
|
"CertKey":"$NETBIRD_MGMT_API_CERT_KEY_FILE",
|
||||||
|
"OIDCConfigEndpoint":"$NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT"
|
||||||
},
|
},
|
||||||
"IdpManagerConfig": {
|
"IdpManagerConfig": {
|
||||||
"Manager": "none"
|
"Manager": "none"
|
||||||
}
|
},
|
||||||
|
"DeviceAuthorizationFlow": {
|
||||||
|
"Provider": "$NETBIRD_AUTH_DEVICE_AUTH_PROVIDER",
|
||||||
|
"ProviderConfig": {
|
||||||
|
"Audience": "$NETBIRD_AUTH_AUDIENCE",
|
||||||
|
"Domain": "$NETBIRD_AUTH0_DOMAIN",
|
||||||
|
"ClientID": "$NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID",
|
||||||
|
"TokenEndpoint": "$NETBIRD_AUTH_TOKEN_ENDPOINT",
|
||||||
|
"DeviceAuthEndpoint": "$NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,16 +2,14 @@
|
|||||||
##
|
##
|
||||||
# Dashboard domain. e.g. app.mydomain.com
|
# Dashboard domain. e.g. app.mydomain.com
|
||||||
NETBIRD_DOMAIN=""
|
NETBIRD_DOMAIN=""
|
||||||
# e.g. https://dev-24vkclam.us.auth0.com/ or https://YOUR-KEYCLOAK-HOST:8080/realms/netbird
|
# OIDC configuration e.g., https://example.eu.auth0.com/.well-known/openid-configuration
|
||||||
NETBIRD_AUTH_AUTHORITY=""
|
NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT=""
|
||||||
|
NETBIRD_AUTH_AUDIENCE=""
|
||||||
# e.g. netbird-client
|
# e.g. netbird-client
|
||||||
NETBIRD_AUTH_CLIENT_ID=""
|
NETBIRD_AUTH_CLIENT_ID=""
|
||||||
# indicates whether to use Auth0 or not: true or false
|
# indicates whether to use Auth0 or not: true or false
|
||||||
NETBIRD_USE_AUTH0="false"
|
NETBIRD_USE_AUTH0="false"
|
||||||
# a list of scopes supported e.g. `openid profile email offline_access api` for keycloak or `openid profile email offline_access api email_verified` for Auth0
|
NETBIRD_AUTH_DEVICE_AUTH_PROVIDER="none"
|
||||||
NETBIRD_AUTH_SUPPORTED_SCOPES=""
|
NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID=""
|
||||||
NETBIRD_AUTH_AUDIENCE=""
|
|
||||||
# URL of the JWT certificates e.g. https://dev-24vkclam.us.auth0.com/.well-known/jwks.json
|
|
||||||
NETBIRD_AUTH_JWT_CERTS=""
|
|
||||||
# e.g. hello@mydomain.com
|
# e.g. hello@mydomain.com
|
||||||
NETBIRD_LETSENCRYPT_EMAIL=""
|
NETBIRD_LETSENCRYPT_EMAIL=""
|
@ -3,15 +3,11 @@
|
|||||||
# Dashboard domain. e.g. app.mydomain.com
|
# Dashboard domain. e.g. app.mydomain.com
|
||||||
NETBIRD_DOMAIN="localhost"
|
NETBIRD_DOMAIN="localhost"
|
||||||
# e.g. https://dev-24vkclam.us.auth0.com/ or https://YOUR-KEYCLOAK-HOST:8080/realms/netbird
|
# e.g. https://dev-24vkclam.us.auth0.com/ or https://YOUR-KEYCLOAK-HOST:8080/realms/netbird
|
||||||
NETBIRD_AUTH_AUTHORITY=$CI_NETBIRD_AUTH_AUTHORITY
|
NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT="https://example.eu.auth0.com/.well-known/openid-configuration"
|
||||||
# e.g. netbird-client
|
# e.g. netbird-client
|
||||||
NETBIRD_AUTH_CLIENT_ID=$CI_NETBIRD_AUTH_CLIENT_ID
|
NETBIRD_AUTH_CLIENT_ID=$CI_NETBIRD_AUTH_CLIENT_ID
|
||||||
# indicates whether to use Auth0 or not: true or false
|
# indicates whether to use Auth0 or not: true or false
|
||||||
NETBIRD_USE_AUTH0=$CI_NETBIRD_USE_AUTH0
|
NETBIRD_USE_AUTH0=$CI_NETBIRD_USE_AUTH0
|
||||||
# a list of scopes supported e.g. `openid profile email offline_access api` for keycloak or `openid profile email offline_access api email_verified` for Auth0
|
|
||||||
NETBIRD_AUTH_SUPPORTED_SCOPES=$CI_NETBIRD_AUTH_SUPPORTED_SCOPES
|
|
||||||
NETBIRD_AUTH_AUDIENCE=$CI_NETBIRD_AUTH_AUDIENCE
|
NETBIRD_AUTH_AUDIENCE=$CI_NETBIRD_AUTH_AUDIENCE
|
||||||
# URL of the JWT certificates e.g. https://dev-24vkclam.us.auth0.com/.well-known/jwks.json
|
|
||||||
NETBIRD_AUTH_JWT_CERTS=$CI_NETBIRD_AUTH_JWT_CERTS
|
|
||||||
# e.g. hello@mydomain.com
|
# e.g. hello@mydomain.com
|
||||||
NETBIRD_LETSENCRYPT_EMAIL=""
|
NETBIRD_LETSENCRYPT_EMAIL=""
|
@ -324,7 +324,7 @@ func loadMgmtConfig(mgmtConfigPath string) (*server.Config, error) {
|
|||||||
oidcConfig.JwksURI, config.HttpConfig.AuthKeysLocation)
|
oidcConfig.JwksURI, config.HttpConfig.AuthKeysLocation)
|
||||||
config.HttpConfig.AuthKeysLocation = oidcConfig.JwksURI
|
config.HttpConfig.AuthKeysLocation = oidcConfig.JwksURI
|
||||||
|
|
||||||
if config.DeviceAuthorizationFlow != nil {
|
if !(config.DeviceAuthorizationFlow == nil || strings.ToLower(config.DeviceAuthorizationFlow.Provider) == string(server.NONE)) {
|
||||||
log.Infof("overriding DeviceAuthorizationFlow.TokenEndpoint with a new value: %s, previously configured value: %s",
|
log.Infof("overriding DeviceAuthorizationFlow.TokenEndpoint with a new value: %s, previously configured value: %s",
|
||||||
oidcConfig.TokenEndpoint, config.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint)
|
oidcConfig.TokenEndpoint, config.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint)
|
||||||
config.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint = oidcConfig.TokenEndpoint
|
config.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint = oidcConfig.TokenEndpoint
|
||||||
@ -339,7 +339,6 @@ func loadMgmtConfig(mgmtConfigPath string) (*server.Config, error) {
|
|||||||
log.Infof("overriding DeviceAuthorizationFlow.ProviderConfig.Domain with a new value: %s, previously configured value: %s",
|
log.Infof("overriding DeviceAuthorizationFlow.ProviderConfig.Domain with a new value: %s, previously configured value: %s",
|
||||||
u.Host, config.DeviceAuthorizationFlow.ProviderConfig.Domain)
|
u.Host, config.DeviceAuthorizationFlow.ProviderConfig.Domain)
|
||||||
config.DeviceAuthorizationFlow.ProviderConfig.Domain = u.Host
|
config.DeviceAuthorizationFlow.ProviderConfig.Domain = u.Host
|
||||||
|
|
||||||
}
|
}
|
||||||
if config.IdpManagerConfig != nil {
|
if config.IdpManagerConfig != nil {
|
||||||
log.Infof("overriding Auth0ClientCredentials.AuthIssuer with a new value: %s, previously configured value: %s",
|
log.Infof("overriding Auth0ClientCredentials.AuthIssuer with a new value: %s, previously configured value: %s",
|
||||||
|
@ -16,7 +16,7 @@ const (
|
|||||||
TCP Protocol = "tcp"
|
TCP Protocol = "tcp"
|
||||||
HTTP Protocol = "http"
|
HTTP Protocol = "http"
|
||||||
HTTPS Protocol = "https"
|
HTTPS Protocol = "https"
|
||||||
AUTH0 Provider = "auth0"
|
NONE Provider = "none"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config of the Management service
|
// Config of the Management service
|
||||||
|
@ -491,7 +491,7 @@ func (s *GRPCServer) GetDeviceAuthorizationFlow(ctx context.Context, req *proto.
|
|||||||
return nil, status.Error(codes.InvalidArgument, errMSG)
|
return nil, status.Error(codes.InvalidArgument, errMSG)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.config.DeviceAuthorizationFlow == nil {
|
if s.config.DeviceAuthorizationFlow == nil || s.config.DeviceAuthorizationFlow.Provider == string(NONE) {
|
||||||
return nil, status.Error(codes.NotFound, "no device authorization flow information available")
|
return nil, status.Error(codes.NotFound, "no device authorization flow information available")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user