Google Tutorial
View SourceThis is a quick tutorial on how to configure Google authentication.
First you'll need a registered application in Google Cloud, in order to get your OAuth 2.0 Client credentials.
- On the Cloud's console Quick access section select APIs & Services, then Credentials
- Click on + CREATE CREDENTIALS and from the dropdown select OAuth client ID
- From the google developers console, we will need:
client_id&client_secret - Enter your callback uri under Authorized redirect URIs. E.g.
http://localhost:4000/auth/user/google/callback.
Next we configure our resource to use google credentials:
defmodule MyApp.Accounts.User do
use Ash.Resource,
extensions: [AshAuthentication],
domain: MyApp.Accounts
attributes do
...
end
authentication do
strategies do
google do
client_id MyApp.Secrets
redirect_uri MyApp.Secrets
client_secret MyApp.Secrets
identity_resource MyApp.Accounts.UserIdentity
end
end
end
endPlease check the guide on how to properly configure your Secrets.
The user identity resource
OAuth2-based strategies require an identity_resource - a resource that stores
the provider's iss (issuer) and sub (subject) claims for each linked
account. Matching a returning user by their email address (or any other claim)
is not safe: per the OpenID Connect specification only the iss/sub
combination uniquely and stably identifies an end-user. The identity resource is
where those values live.
Returning users are matched by their iss/sub. Because Google reliably
verifies email ownership, trust_email_verified? defaults to true for this
strategy, so a new Google identity whose verified email matches an existing
local account is linked to it automatically.
Add a UserIdentity resource using the AshAuthentication.UserIdentity
extension. There is no need to define any attributes - the extension generates
them for you.
defmodule MyApp.Accounts.UserIdentity do
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [AshAuthentication.UserIdentity],
domain: MyApp.Accounts
user_identity do
user_resource MyApp.Accounts.User
end
# Configure your data layer as appropriate for your application.
postgres do
table "user_identities"
repo MyApp.Repo
end
endDon't forget to add it to your domain, and to generate and run migrations for the new resource.
mix ash.codegen add_user_identities
mix ash.migrate
Then we need to define an action that will handle the oauth2 flow, for the google case it is :register_with_google it will handle both cases for our resource, user registration & login.
defmodule MyApp.Accounts.User do
require Ash.Resource.Change.Builtins
use Ash.Resource,
extensions: [AshAuthentication],
domain: MyApp.Accounts
# ...
actions do
create :register_with_google do
argument :user_info, :map, allow_nil?: false
argument :oauth_tokens, :map, allow_nil?: false
upsert? true
upsert_identity :unique_email
change AshAuthentication.GenerateTokenChange
# Required: persists the provider's `iss`/`sub` identity claims.
change AshAuthentication.Strategy.OAuth2.IdentityChange
change fn changeset, _ ->
user_info = Ash.Changeset.get_argument(changeset, :user_info)
Ash.Changeset.change_attributes(changeset, Map.take(user_info, ["email"]))
end
# Required if you're using the password & confirmation strategies
upsert_fields []
change set_attribute(:confirmed_at, &DateTime.utc_now/0)
end
end
# ...
endEnsure you set the hashed_password to allow_nil? if you are also using the password strategy.
defmodule MyApp.Accounts.User do
# ...
attributes do
# ...
attribute :hashed_password, :string, allow_nil?: true, sensitive?: true
end
# ...
endAnd generate and run migrations in that case.
mix ash.codegen make_hashed_password_nullable
mix ash.migrate