Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

| Area | Supported Standards & Features |
| :--- | :--- |
| **OAuth 2.0 Grants** | Authorization Code (`authorization_code`), Client Credentials (`client_credentials`), Refresh Token (`refresh_token` with rotation & family reuse detection), Device Authorization (`urn:ietf:params:oauth:grant-type:device_code`), Cryptographic Challenge-Response (`challenge_response` / `urn:ietf:params:oauth:grant-type:challenge`), Password (`password`), Implicit (`implicit`) |
| **OAuth 2.0 Grants** | Authorization Code (`authorization_code`), Client Credentials (`client_credentials`), Refresh Token (`refresh_token` with rotation & family reuse detection), Device Authorization (`urn:ietf:params:oauth:grant-type:device_code`), Cryptographic Challenge-Response (`challenge_response` / `urn:ietf:params:oauth:grant-type:challenge`), Social Sign-In (`social` / `urn:ietf:params:oauth:grant-type:social`), Password (`password`), Implicit (`implicit`) |
| **Social Sign-In** | Built-in adapters for **Google**, **GitHub**, **Apple**, **Microsoft / Entra ID**, **Discord**, and generic OAuth2/OIDC providers (`GET /oauth/social/:provider`, `GET\|POST /oauth/social/:provider/callback`, and `POST /oauth/token`) |
| **OpenID Connect** | `id_token` issuance (`nonce`, `acr`, `amr`, `auth_time`), `GET /oauth/userinfo`, OIDC Discovery (`/.well-known/openid-configuration`), OAuth 2.0 Authorization Server Metadata (`/.well-known/oauth-authorization-server` — RFC 8414), JWKS (`/.well-known/jwks.json` — RFC 7517) |
| **FAPI & Advanced Security** | PKCE with `S256` enforcement (RFC 7636), Pushed Authorization Requests (`POST /oauth/par` — RFC 9126), JWT Secured Authorization Response Mode (JARM — RFC 9101), Certificate-Bound Access Tokens (`cnf.x5t#S256` mTLS — RFC 8705), Dynamic Client Registration (`POST /oauth/register` — RFC 7591) |
| **Token Lifecycle** | `:jwt` (`HS*`, `RS*`, `ES*`) and `:opaque` token strategies, asymmetric key rotation (`signing_key_id` + `verification_keys`), Token Introspection (`POST /oauth/introspect` — RFC 7662), Token Revocation (`POST /oauth/revoke` — RFC 7009), host-controlled `IssuanceOptions` |
Expand Down Expand Up @@ -137,6 +138,7 @@ Practical recipes for configuring production features:
- **[Enable FAPI & Advanced Security (PKCE, PAR, JARM, mTLS)](docs/how-to/fapi-and-advanced-security.md)** — Enforce `S256` PKCE, Pushed Authorization Requests (`POST /oauth/par`), JARM signed/encrypted responses, and certificate-bound tokens.
- **[Configure Asymmetric Keys, Key Rotation & JWKS](docs/how-to/key-rotation-and-jwks.md)** — Sign with `RS256` / `ES256`, rotate keys without downtime via `verification_keys`, and customize claims with `IssuanceOptions`.
- **[Configure Dynamic Client Registration & Device Authorization](docs/how-to/dynamic-client-registration.md)** — Enable RFC 7591 registration (`POST /oauth/register`) and RFC 8628 smart-TV/CLI device flows (`POST /oauth/device/code` & `/device`).
- **[Configure Social Sign-In](docs/how-to/social-sign-in.md)** — Integrate Google, GitHub, Apple, Microsoft, Discord, and custom OAuth2/OIDC providers via redirect callbacks or `POST /oauth/token`.

### [Reference](docs/reference/README.md)
Complete technical specifications:
Expand All @@ -163,6 +165,8 @@ Architectural overviews and security design:
| `POST` | `/oauth/token` | Token issuance & refresh (`authorization_code`, `client_credentials`, `refresh_token`, `password`, `device_code`, `challenge_response`) |
| `POST` | `/oauth/par` | Pushed Authorization Requests (RFC 9126) |
| `POST` | `/oauth/challenge` | Cryptographic Challenge-Response nonce issuance |
| `GET` | `/oauth/social/:provider` | Social Sign-In redirect initiation (PKCE + signed CSRF `state`) |
| `GET`, `POST` | `/oauth/social/:provider/callback` | Social Sign-In provider callback |
| `POST` | `/oauth/device/code` | Device Authorization code issuance (RFC 8628) |
| `GET`, `POST` | `/device` | End-user device code verification page (RFC 8628) |
| `POST` | `/oauth/introspect`, `/introspect` | Token Introspection (RFC 7662) |
Expand Down
1 change: 1 addition & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* [Enable FAPI & Advanced Security (PKCE, PAR, JARM, mTLS)](how-to/fapi-and-advanced-security.md)
* [Configure Asymmetric Keys, Key Rotation & JWKS](how-to/key-rotation-and-jwks.md)
* [Configure Dynamic Client Registration & Device Flow](how-to/dynamic-client-registration.md)
* [Configure Social Sign-In (Google, GitHub, Apple, Microsoft, Discord)](how-to/social-sign-in.md)

## Reference

Expand Down
4 changes: 4 additions & 0 deletions docs/how-to/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ These guides show you how to solve specific problems in production—such as con
{% content-ref url="dynamic-client-registration.md" %}
[dynamic-client-registration.md](dynamic-client-registration.md)
{% endcontent-ref %}

{% content-ref url="social-sign-in.md" %}
[social-sign-in.md](social-sign-in.md)
{% endcontent-ref %}
151 changes: 151 additions & 0 deletions docs/how-to/social-sign-in.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
description: Configure Google, GitHub, Apple, Microsoft, Discord, and custom OAuth2/OIDC social sign-in flows.
icon: users
---

# Configure Social Sign-In

Authly provides built-in Social Sign-In support for **Google**, **GitHub**, **Apple**, **Microsoft / Entra ID**, **Discord**, and any custom OAuth 2.0 / OIDC identity provider (`Authly::Social::GenericOAuth2`).

It supports two complementary flows:
1. **Browser Redirect & Callback Flow** (`GET /oauth/social/:provider` and `GET|POST /oauth/social/:provider/callback`) with automatic `S256` PKCE and single-use signed CSRF `state` tokens.
2. **Token Endpoint Grant Exchange** (`POST /oauth/token` with `grant_type=social` or `urn:ietf:params:oauth:grant-type:social`) for native mobile apps, SPAs, and backend services.

---

## 1. Register Social Providers

{% tabs %}
{% tab title="Google, GitHub & Apple" %}
```crystal
Authly.configure do |config|
config.register_social_provider(
Authly::Social::Google.new(
client_id: ENV["GOOGLE_CLIENT_ID"],
client_secret: ENV["GOOGLE_CLIENT_SECRET"],
redirect_uri: "https://auth.example.com/oauth/social/google/callback"
)
)

config.register_social_provider(
Authly::Social::GitHub.new(
client_id: ENV["GITHUB_CLIENT_ID"],
client_secret: ENV["GITHUB_CLIENT_SECRET"],
redirect_uri: "https://auth.example.com/oauth/social/github/callback"
)
)

config.register_social_provider(
Authly::Social::Apple.new(
client_id: ENV["APPLE_SERVICE_ID"],
client_secret: ENV["APPLE_CLIENT_SECRET"],
redirect_uri: "https://auth.example.com/oauth/social/apple/callback"
)
)
end
```
{% endtab %}

{% tab title="Microsoft, Discord & Custom Provider" %}
```crystal
Authly.configure do |config|
config.register_social_provider(
Authly::Social::Microsoft.new(
client_id: ENV["MS_CLIENT_ID"],
client_secret: ENV["MS_CLIENT_SECRET"],
redirect_uri: "https://auth.example.com/oauth/social/microsoft/callback",
tenant: "common"
)
)

config.register_social_provider(
Authly::Social::Discord.new(
client_id: ENV["DISCORD_CLIENT_ID"],
client_secret: ENV["DISCORD_CLIENT_SECRET"],
redirect_uri: "https://auth.example.com/oauth/social/discord/callback"
)
)

config.register_social_provider(
Authly::Social::GenericOAuth2.new(
name: "gitlab",
client_id: ENV["GITLAB_CLIENT_ID"],
client_secret: ENV["GITLAB_CLIENT_SECRET"],
redirect_uri: "https://auth.example.com/oauth/social/gitlab/callback",
authorize_endpoint: "https://gitlab.com/oauth/authorize",
token_endpoint: "https://gitlab.com/oauth/token",
userinfo_endpoint: "https://gitlab.com/oauth/userinfo"
)
)
end
```
{% endtab %}
{% endtabs %}

---

## 2. Map Social Profiles to Local Resource Owners

When a user completes social sign-in, Authly normalizes their upstream identity into an `Authly::SocialProfile` (`provider`, `uid`, `email`, `email_verified?`, `name`, `first_name`, `last_name`, `nickname`, `avatar_url`, `raw_attributes`).

You can map `SocialProfile` to a local subject ID either on your `AuthorizableOwner` store or via `config.social_owner_resolver`:

{% tabs %}
{% tab title="config.social_owner_resolver" %}
```crystal
Authly.configure do |config|
config.social_owner_resolver = ->(profile : Authly::SocialProfile) : String? {
# Find or provision a user in your database
user = UserRepo.find_by_social(profile.provider, profile.uid)
if user.nil? && profile.email_verified?
if email = profile.email
user = UserRepo.find_or_create_by_email(email, name: profile.name, avatar: profile.avatar_url)
UserRepo.link_social(user.id, profile.provider, profile.uid)
end
end
user.try(&.id)
}
end
```
{% endtab %}

{% tab title="AuthorizableOwner#resolve_social_owner" %}
```crystal
class DatabaseOwners
include Authly::AuthorizableOwner

def resolve_social_owner(profile : Authly::SocialProfile) : String?
UserRepo.resolve_or_create_from_social(profile)
end

# ... authorized? and id_token ...
end
```
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
**Fail-Closed Account Linking**: Only auto-link a social account to an existing email address when `profile.email_verified?` is `true`. If `resolve_social_owner` returns `nil`, Authly refuses the login with `403 access_denied`.
{% endhint %}

---

## 3. Flow A: Browser Redirect & Callback (`/oauth/social/:provider`)

1. **Direct Sign-In**: Redirect the browser to `GET /oauth/social/google?scope=read+openid`. Upon callback at `/oauth/social/google/callback`, Authly verifies the signed `state` token, consumes its single-use nonce in `state_store`, exchanges the `code` with PKCE `code_verifier`, and returns `200 OK` JSON with an `AccessToken` (or invokes `config.on_social_authenticated` to set your app's session cookie).
2. **OAuth2 Client Code Flow**: Pass `client_id`, `redirect_uri`, `scope`, and `state` to `GET /oauth/social/google?client_id=my-app&redirect_uri=https://app.example.com/cb&scope=read+openid&state=xyz`. Upon callback, Authly redirects to `https://app.example.com/cb?code=<authly_code>&state=xyz`.

---

## 4. Flow B: Token Endpoint Grant Exchange (`POST /oauth/token`)

Mobile apps and SPAs that obtain an authorization `code` or `subject_token` / `id_token` directly from a social SDK can exchange it at `POST /oauth/token`:

```bash
curl -X POST https://auth.example.com/oauth/token \
-u "my-client:my-secret" \
-d "grant_type=social" \
-d "provider=google" \
-d "code=4/0AfJohXl..." \
-d "scope=read openid"
```
Loading
Loading