Skip to content

Commit

Permalink
add microsoft oauth authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
banux committed May 8, 2020
1 parent 0268846 commit f6ea426
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 2 deletions.
3 changes: 3 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ func NewApp(cfg *Config, logger logrus.FieldLogger) (*App, error) {
if cfg.DiscordOauthCredentials != nil {
oauthProviders["discord"] = *oauth.NewDiscordProvider(cfg.DiscordOauthCredentials)
}
if cfg.MicrosoftOauthCredientials != nil {
oauthProviders["microsoft"] = *oauth.NewMicrosoftProvider(cfg.MicrosoftOauthCredientials)
}

return &App{
// Provide access to root DB - useful when extending AccountStore functionality
Expand Down
17 changes: 16 additions & 1 deletion app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,16 @@ type Config struct {
GitHubOauthCredentials *oauth.Credentials
FacebookOauthCredentials *oauth.Credentials
DiscordOauthCredentials *oauth.Credentials
MicrosoftOauthCredientials *oauth.Credentials
}

// OAuthEnabled returns true if any provider is configured.
func (c *Config) OAuthEnabled() bool {
return c.GoogleOauthCredentials != nil ||
c.GitHubOauthCredentials != nil ||
c.FacebookOauthCredentials != nil ||
c.DiscordOauthCredentials != nil
c.DiscordOauthCredentials != nil ||
c.MicrosoftOauthCredientials != nil
}

// SameSiteComputed returns either the specified http.SameSite, or a computed one from OAuth config
Expand Down Expand Up @@ -563,6 +565,19 @@ var configurers = []configurer{
}
return nil
},

// Microsoft_OAUTH_CREDENTIALS is a credential pair in the format `id:secret`. When specified,
// AuthN will enable routes for Discord OAuth signin.
func(c *Config) error {
if val, ok := os.LookupEnv("MICROSOFT_OAUTH_CREDENTIALS"); ok {
credentials, err := oauth.NewCredentials(val)
if err == nil {
c.MicrosoftOauthCredientials = credentials
}
return err
}
return nil
},
}

// ReadEnv returns a Config struct from environment variables. It returns errors when a variable is
Expand Down
12 changes: 11 additions & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Databases: [`DATABASE_URL`](#database_url)[`REDIS_URL`](#redis_url)
* Sessions:
[`ACCESS_TOKEN_TTL`](#access_token_ttl)[`REFRESH_TOKEN_TTL`](#refresh_token_ttl)[`SESSION_KEY_SALT`](#session_key_salt)[`DB_ENCRYPTION_KEY_SALT`](#db_encryption_key_salt)[`RSA_PRIVATE_KEY`](#rsa_private_key)[`SAME_SITE](#same_site)
* OAuth Clients: [`FACEBOOK_OAUTH_CREDENTIALS`](#facebook_oauth_credentials)[`GITHUB_OAUTH_CREDENTIALS`](#github_oauth_credentials)[`GOOGLE_OAUTH_CREDENTIALS`](#google_oauth_credentials)[`DISCORD_OAUTH_CREDENTIALS`](#discord_oauth_credentials)
* OAuth Clients: [`FACEBOOK_OAUTH_CREDENTIALS`](#facebook_oauth_credentials)[`GITHUB_OAUTH_CREDENTIALS`](#github_oauth_credentials)[`GOOGLE_OAUTH_CREDENTIALS`](#google_oauth_credentials)[`DISCORD_OAUTH_CREDENTIALS`](#discord_oauth_credentials)[`MICROSOFT_OAUTH_CREDENTIALS`](#microsoft_oauth_credentials)
* Username Policy: [`USERNAME_IS_EMAIL`](#username_is_email)[`EMAIL_USERNAME_DOMAINS`](#email_username_domains)
* Password Policy: [`PASSWORD_POLICY_SCORE`](#password_policy_score)[`PASSWORD_CHANGE_LOGOUT`](#password_change_logout)[`BCRYPT_COST`](#bcrypt_cost)
* Password Resets: [`APP_PASSWORD_RESET_URL`](#app_password_reset_url)[`PASSWORD_RESET_TOKEN_TTL`](#password_reset_token_ttl)[`APP_PASSWORD_CHANGED_URL`](#app_password_changed_url)
Expand Down Expand Up @@ -242,6 +242,16 @@ Sign up for Google OAuth 2.0 credentials with the instructions here: https://dev

Sign up for Discord OAuth 2.0 credentials with the instructions here: https://discordapp.com/developers/docs/topics/oauth2. Your client's ID and secret must be joined together with a `:` and provided to AuthN as a single variable.

### `MICROSOFT_OAUTH_CREDENTIALS`

| | |
| --------- | --- |
| Required? | No |
| Value | ClientID:ClientSecret |
| Default | nil |

Sign up for Microsoft OAuth 2.0 credentials with the instructions here: https://docs.microsoft.com/fr-fr/graph/auth/. Your client's ID and secret must be joined together with a `:` and provided to AuthN as a single variable.

## Username Policy

### `USERNAME_IS_EMAIL`
Expand Down
53 changes: 53 additions & 0 deletions lib/oauth/microsoft.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package oauth

import (
"context"
"encoding/json"
"fmt"
"io/ioutil"

"golang.org/x/oauth2"
)

// NewMicrosoftProvider returns a AuthN integration for Microsoft OAuth
func NewMicrosoftProvider(credentials *Credentials) *Provider {
config := &oauth2.Config{
ClientID: credentials.ID,
ClientSecret: credentials.Secret,
Scopes: []string{"openid", "user.read", "user.read.all"},
Endpoint: oauth2.Endpoint{
AuthURL: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
TokenURL: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
},
}

return &Provider{
config: config,
UserInfo: func(t *oauth2.Token) (*UserInfo, error) {
var me struct {
id string
userPrincipalName string
}

client := config.Client(context.TODO(), t)
resp, err := client.Get("https://graph.microsoft.com/v1.0/me")
if err != nil {
return nil, err
}
defer resp.Body.Close()

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
fmt.Println(string(body))

var user UserInfo
err = json.Unmarshal(body, &me)
user.ID = me.id
user.Email = me.userPrincipalName
fmt.Println(user)
return &user, err
},
}
}

0 comments on commit f6ea426

Please sign in to comment.