-
Notifications
You must be signed in to change notification settings - Fork 90
Supported Scenarios
Hemanth Chittanuru edited this page Aug 6, 2020
·
1 revision
Username and Password token acquisition flow has some restrictions, and this is detailed here
func tryUsernamePassword() {
userNameParams := msalgo.CreateAcquireTokenUsernamePasswordParameters(config.Scopes, config.Username, config.Password)
result, err := publicClientApp.AcquireTokenByUsernamePassword(userNameParams)
if err != nil {
log.Fatal(err)
}
accessToken := result.GetAccessToken()
log.Info("Access token is: " + accessToken)
}
//config has all the values required for token acquisition
publicClientApp, err := publicClientApp, err := msalgo.CreatePublicClientApplication(config.ClientID, config.Authority)
if err != nil {
log.Fatal(err)
}
//Checking to see if there is an account with the same username in the cache
var userAccount msalgo.AccountInterfacer
accounts := publicClientApp.GetAccounts()
for _, account := range accounts {
if account.GetUsername() == config.Username {
userAccount = account
}
}
//If an account with the same username exists, try to acquire the token silently
if userAccount != nil {
silentParams := msalgo.CreateAcquireTokenSilentParametersWithAccount(config.Scopes, userAccount)
result, err := publicClientApp.AcquireTokenSilent(silentParams)
if err != nil {
//If this is not possible, try username-password flow
tryUsernamePassword()
} else {
accessToken := result.GetAccessToken()
log.Info("Access token is: " + accessToken)
}
} else {
//If the account doesn't exist, try username-password flow
tryUsernamePassword()
}
func deviceCodeCallback(deviceCodeResult msalgo.IDeviceCodeResult) {
log.Infof(deviceCodeResult.GetMessage())
}
func tryDeviceCodeFlow(publicClientApp *msalgo.PublicClientApplication) {
// This cancel timeout can be set by the user to cancel the device code request after a certain interval
cancelTimeout := 100
cancelCtx, cancelFunc := context.WithTimeout(context.Background(), time.Duration(cancelTimeout)*time.Second)
defer cancelFunc()
// The device code callback is used to print the device code message to the user
deviceCodeParams := msalgo.CreateAcquireTokenDeviceCodeParameters(cancelCtx, config.Scopes, deviceCodeCallback)
// The channels are used as there is user interaction required (entering the device code at the verification URL)
resultChannel := make(chan msalgo.AuthenticationResultInterfacer)
errChannel := make(chan error)
go func() {
result, err := publicClientApp.AcquireTokenByDeviceCode(deviceCodeParams)
errChannel <- err
resultChannel <- result
}()
err = <-errChannel
if err != nil {
log.Fatal(err)
}
result := <-resultChannel
fmt.Println("Access token is " + result.GetAccessToken())
}
//config has all the values required for token acquisition
publicClientApp, err := msalgo.CreatePublicClientApplication(config.ClientID, config.Authority)
if err != nil {
log.Fatal(err)
}
//Try silent token acquistion, but this can be skipped
//Assuming the account we want is the first one
var userAccount msalgo.AccountInterfacer
accounts := publicClientApp.GetAccounts()
if len(accounts) == 0 {
userAccount = nil
} else {
userAccount = accounts[0]
}
//If the account doesn't exist, try device code flow
if userAccount == nil {
tryDeviceCodeFlow(publicClientApp)
} else {
silentParams := msalgo.CreateAcquireTokenSilentParametersWithAccount(config.Scopes, userAccount)
result, err := publicClientApp.AcquireTokenSilent(silentParams)
//If there is an error with silent acquisition, try device code flow
if err != nil {
log.Info(err)
tryDeviceCodeFlow(publicClientApp)
} else {
fmt.Println("Access token is " + result.GetAccessToken())
}
}
MSAL Go doesn't provide an interactive acquire token method directly. Instead, it requires the application to send an authorization request in its implementation of the user interaction flow to obtain an authorization code. This code can then be used in the authorization code flow to get the token.
func tryAuthCodeFlow(code string) {
authCodeParams := msalgo.CreateAcquireTokenAuthCodeParameters(config.Scopes, config.RedirectURI, config.CodeChallenge)
authCodeParams.Code = code
result, err := publicClientApp.AcquireTokenByAuthCode(authCodeParams)
if err != nil {
log.Fatal(err)
}
fmt.Println("Access token is " + result.GetAccessToken())
}
//Try silent token acquistion, but this can be skipped
//Assuming the account we want is the first one
var userAccount msalgo.AccountInterfacer
accounts := publicClientApp.GetAccounts()
if len(accounts) == 0 {
userAccount = nil
} else {
userAccount = accounts[0]
}
//If the account doesn't exist, try auth code flow
if userAccount == nil {
tryAuthCodeFlow(authCode)
} else {
silentParams := msalgo.CreateAcquireTokenSilentParametersWithAccount(config.Scopes, userAccount)
result, err := publicClientApp.AcquireTokenSilent(silentParams)
//If there is an error with silent acquisition, try auth code flow
if err != nil {
log.Info(err)
tryAuthCodeFlow(authCode)
} else {
fmt.Println("Access token is " + result.GetAccessToken())
}
}
//Creating a client credential using a client secret
secret, err := msalgo.CreateClientCredentialFromSecret(config.ClientSecret)
if err != nil {
log.Fatal(err)
}
//Creating the confidential client app instance
confidentialClientApp, err := msalgo.CreateConfidentialClientApplication(
clientID, authority, secret)
if err != nil {
log.Fatal(err)
}
//Try to acquire token from cache
silentParams := msalgo.CreateAcquireTokenSilentParameters(confidentialConfig.Scopes)
result, err := confidentialClientApp.AcquireTokenSilent(silentParams)
//If no token in cache, use the client secret
if err != nil {
log.Info(err)
clientSecretParams := msalgo.CreateAcquireTokenClientCredentialParameters(confidentialConfig.Scopes)
result, err := confidentialClientApp.AcquireTokenByClientCredential(clientSecretParams)
if err != nil {
log.Fatal(err)
}
}
accessToken := result.GetAccessToken()
log.Info("Access token is: " + accessToken)