Documentation
¶
Overview ¶
Package google provides authentication via Google SSO.
Two methods of authentication are supported: - Client side via the Google SDK. - Server side via the OAuth2 flow.
## Client side authentication
The client side flow uses the Google SDK to retrieve an identity token, which is then passed to the server for validation.
1. The user clicks on the "Sign in with Google" button. 2. The Google SDK opens a popup window. 3. The user logs in and grants access to the app. 4. The Google SDK returns an identity token to a javascript callback. 5. The client passes the identity token to the server's login endpoint. 6. The server validates the token and sets a cookie. 7. Subsequent API requests are authenticated via the cookie.
A non-cookie option is to pass `issue_token` in the login endpoint, which will prompt the server to return an access token without setting cookies.
## Server side authentication
https://developers.google.com/identity/protocols/oauth2/web-server#httprest
To initiate a server side login, the client should make a POST request to the `/api/auth/login` endpoint with the following JSON body:
```json
{
"provider": "google",
"redirect_uri": "/dashboard"
}
```
The server will respond with a JSON object containing a `redirect_uri` field, which the client should redirect the user to.
A GET request may also be used, with the `provider` being passed as a query parameter. The response will be sent with a 301 status code, which can be used to redirect the user directly to Google if needed, short circuiting steps 1-3 below. When making a `fetch` request ensure that it is configured to not follow redirects.
The full flow is as follows:
1. The client requests a login URL from the server. 2. The client redirects to the URL. 3. The user logs in and grants access to the app. 4. Google redirects the user back to the server with an authorization code. 5. The server exchanges the authorization code for an access token. 6. The server uses the access token to fetch the user's profile. 7. The server creates an identity token and sets a cookie. 8. The server redirects the user to the destination specified in the original request. 9. Subsequent API requests are authenticated via the cookie.
## Configuring Google OAuth App
Follow the official steps here: https://support.google.com/cloud/answer/6158849
For development the Authorized redirect URIs should be set to: http://localhost:8000/api/auth/google/callback
In production switch out the protocol, host, and port with your domain.
Index ¶
Constants ¶
const ( // Constant name for the Google auth plugin. PluginName = "auth_google" // Constant name used as the auth provider in API requests. ProviderName = "google" )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type GoogleOption ¶
type GoogleOption func(*GooglePlugin)
GoogleOptions allow configuration of the GooglePlugin.
func WithClient ¶
func WithClient(id, secret string) GoogleOption
WithClient configures the GooglePlugin with the given client id and secret.
func WithOfflineAccess ¶
func WithOfflineAccess() GoogleOption
WithOfflineAccess configures the plugin to request offline access from Google. This causes Google to return a refresh token that can be used to obtain new access tokens after the user's session ends.
Note: Google only returns a refresh token on the first authorization or when the user explicitly re-consents. If you need to force a new refresh token, the user must revoke access in their Google account settings.
Use in combination with WithTokenHandler to receive and store the tokens.
func WithScopes ¶
func WithScopes(scopes ...string) GoogleOption
WithScopes adds additional OAuth scopes beyond the default profile and email scopes. Use this to request access to other Google APIs.
Example scopes:
- "https://www.googleapis.com/auth/gmail.readonly" - Read Gmail messages
- "https://www.googleapis.com/auth/calendar.readonly" - Read calendar events
- "https://www.googleapis.com/auth/drive.readonly" - Read Google Drive files
See https://developers.google.com/identity/protocols/oauth2/scopes for a complete list of available scopes.
func WithTokenHandler ¶
func WithTokenHandler(handler TokenHandler) GoogleOption
WithTokenHandler registers a callback that receives OAuth tokens after successful authentication. The handler is called with the authenticated identity and the OAuth tokens before the login event is published.
Use this to store tokens for later use with Google APIs. The application is responsible for securely storing and refreshing tokens as needed.
If the handler returns an error, the login flow is aborted and the error is returned to the user.
Note: The handler is only called for server-side OAuth flows (authorization code). Client-side flows using ID tokens do not provide OAuth tokens.
type GooglePlugin ¶
type GooglePlugin struct {
// contains filtered or unexported fields
}
GooglePlugin for handling Google authentication.
func Plugin ¶
func Plugin(opts ...GoogleOption) *GooglePlugin
Plugin for handling Google authentication.
func (*GooglePlugin) ServerOptions ¶
func (p *GooglePlugin) ServerOptions() []prefab.ServerOption
From prefab.OptionProvider.
type OAuthToken ¶
type OAuthToken struct {
// AccessToken is the token used to authenticate API requests.
AccessToken string
// RefreshToken is used to obtain new access tokens after expiry.
// Only present when offline access is enabled via WithOfflineAccess().
// Google only returns a refresh token on the first authorization, or when
// the user re-consents. Store this securely.
RefreshToken string
// TokenType is the type of token, typically "Bearer".
TokenType string
// Expiry is the time at which the access token expires.
// A zero value means the token does not expire.
Expiry time.Time
}
OAuthToken contains the OAuth2 token data received from Google after a successful authentication. Applications can use this token to access Google APIs on behalf of the user.
func (OAuthToken) HasRefreshToken ¶
func (t OAuthToken) HasRefreshToken() bool
HasRefreshToken returns true if the token includes a refresh token.
func (OAuthToken) IsExpired ¶
func (t OAuthToken) IsExpired() bool
IsExpired returns true if the access token has expired. Returns false if the token has no expiry time set.
type TokenHandler ¶
TokenHandler is called after successful OAuth authentication with Google. The handler receives the authenticated identity and the OAuth tokens.
Applications should use this handler to store tokens for later use, such as accessing Google APIs (Gmail, Calendar, Drive, etc.) on behalf of the user.
The identity parameter contains the authenticated user's information (subject, email, name) that can be used to associate the token with a user in your system.
Returning an error from the handler will abort the login flow and return the error to the user. Return nil to allow the login to proceed normally.
Example:
google.WithTokenHandler(func(ctx context.Context, identity auth.Identity, token google.OAuthToken) error {
return userService.StoreGoogleToken(ctx, identity.Subject, token)
})
type UserInfo ¶
type UserInfo struct {
// The user's unique and stable ID.
ID string `json:"sub"`
// The user's email address.
Email string `json:"email,omitempty"`
// The user's full name.
Name string `json:"name,omitempty"`
// The user's first name.
GivenName string `json:"given_name,omitempty"`
// The user's last name.
FamilyName string `json:"family_name,omitempty"`
// The user's preferred locale.
Locale string `json:"locale,omitempty"`
// URL of the user's picture image.
Picture string `json:"picture,omitempty"`
// The hosted domain e.g. example.com if the user is Google apps user.
Hd string `json:"hd,omitempty"`
// Included for 3rd party emails and some HD accounts.
EmailVerified *bool `json:"email_verified,omitempty"`
}
The result of calling Google's OAuth2 userinfo endpoint response. Per google the email is always verified as they only return the primary email for the account.
func UserInfoFromClaims ¶
UserInfoFromClaims returns a UserInfo struct from the claims map. If the claims are invalid or missing, an error is returned.
func UserInfoFromJSON ¶
UserInfoFromJSON returns a UserInfo struct from the JSON data. If the JSON is invalid, an error is returned.
func (*UserInfo) IsConfirmed ¶
IsConfirmed returns true if Google is authorative and the user is confirmed to be a legitimate user.
> Using the email, email_verified and hd fields you can determine if Google > hosts and is authoritative for an email address. In cases where Google is > authoritative the user is confirmed to be the legitimate account owner. > > Cases where Google is authoritative: > > - email has a @gmail.com suffix, this is a Gmail Account. > - email_verified is true and hd is set, this is a Google Workspace account. > > Users may register for Google Accounts without using Gmail or Google > Workspace. When email does not contain a @gmail.com suffix and hd is absent > Google is not authoritative and password or other challenge methods are > recommended to verify the user. email_verfied can also be true as Google > initially verified the user when the Google Account was created, however > ownership of the third party email account may have since changed.
IsConfirmed() is conservative and only returns true if Google is authorative and the address has been verified. In otherwords, a user may have EmailVerified=true and not be confirmed. Use-case should determine whether to trust the verification.