Skip to content

External Authentication

External authentication maps an external identity provider login result to an AsterDrive local user. The admin entry point is:

text
Admin -> External Authentication

AsterDrive currently supports six provider kinds:

KindBest forBehavior
oidc / OpenID ConnectStandard OIDC identity providersUses issuer discovery, authorization-code flow, PKCE, nonce, and ID Token validation
generic_oauth2 / Generic OAuth2Providers that expose OAuth2 authorization-code + UserInfo but need manual endpointsManually configures authorization / token / userinfo endpoints, uses authorization-code flow with PKCE, and extracts identity from UserInfo
github / GitHubGitHub OAuth App sign-inUses fixed GitHub OAuth endpoints, reads identity fields from /user, and calls /user/emails to accept only the verified primary email
qq / QQQQ Connect website sign-inUses fixed QQ OAuth2 endpoints, reads openid first, then calls get_user_info for profile data and links external identities by openid
google / GoogleGoogle OIDC sign-inUses fixed Google Accounts issuer / discovery, validates the ID token, and links external identities by sub
microsoft / MicrosoftMicrosoft Entra ID / Microsoft Account OIDC sign-inDerives the Microsoft identity platform issuer / discovery from the tenant, validates the ID token, and links external identities by sub

Prefer oidc when the provider supports standard OIDC. Use dedicated providers for GitHub, QQ, Google, and Microsoft. Use generic_oauth2 only when the provider does not have complete OIDC discovery or you intentionally need OAuth2 UserInfo mapping.

Basic Setup

Before creating a provider, confirm:

  1. Admin -> System Settings -> Site Configuration -> Public Site URL is the real external URL
  2. The reverse proxy already handles HTTPS, Host, real client IPs, and large request bodies
  3. An application has been created on the identity provider side, with a Client ID ready
  4. If this is a confidential client, a Client Secret is ready

After saving the provider, the page shows the redirect URI generated by AsterDrive. Register it with the identity provider. The callback path looks like:

text
https://drive.example.com/api/v1/auth/external-auth/{kind}/{provider}/callback

{kind} is oidc, generic_oauth2, github, qq, google, or microsoft, and {provider} is the provider key generated by the server.

Where To Create The App

Before creating the AsterDrive provider, create an application / OAuth client in the identity provider and register the AsterDrive callback URL as a redirect URI.

ProviderWhere to create itRedirect URI field
OIDC / Generic OAuth2Your identity provider admin console, such as the Applications / Clients page in Logto, Authentik, Keycloak, or ZitadelThe callback URL shown after saving the AsterDrive provider; if the IdP requires it upfront, build it from /api/v1/auth/external-auth/{kind}/{provider}/callback
GitHubGitHub user or organization Settings -> Developer settings -> OAuth Apps -> New OAuth AppOAuth App Authorization callback URL
QQQQ Connect management center https://connect.qq.com/manage.html website applicationApplication callback URL / callback domain; use the callback URL shown after saving the AsterDrive provider
GoogleGoogle Cloud Console APIs & Services -> Credentials -> Create Credentials -> OAuth client IDOAuth client Authorized redirect URIs
MicrosoftMicrosoft Entra admin center / Azure portal App registrations -> New registrationAdd a Web redirect URI on the Authentication page; Supported account types should match the tenant choice in AsterDrive

Common Microsoft Supported account types mapping:

  • AsterDrive tenant consumers: choose "Personal Microsoft accounts only"
  • AsterDrive tenant organizations: choose "Accounts in any organizational directory"
  • AsterDrive tenant as a concrete tenant ID: choose accounts in that directory, or choose a multi-tenant organizational option and restrict the tenant in AsterDrive
  • AsterDrive tenant common: choose "Accounts in any organizational directory and personal Microsoft accounts"

If the identity provider asks for an application type, a login provider is usually a Web application / Confidential client. Leave Client Secret blank only when you know the provider supports public clients and does not require a secret.

Common Fields

FieldMeaning
Display nameName shown on the login button
Icon URLMay be a site path such as /static/external-auth/oauth-logo.svg, or an HTTPS image URL. The login page, admin list, and user security page prefer the configured icon and fall back to the provider-kind icon when it fails
Issuer URLRequired for OIDC; optional for Generic OAuth2. For Generic OAuth2, it becomes the identity namespace if set. GitHub / QQ use fixed identity namespaces; Google is fixed to https://accounts.google.com; Microsoft derives it from the tenant
Authorization URLRequired for Generic OAuth2; discovered for OIDC; fixed for GitHub / QQ; discovered from Google / Microsoft fixed discovery
Token URLRequired for Generic OAuth2; discovered for OIDC; fixed for GitHub / QQ; discovered from Google / Microsoft fixed discovery
UserInfo URLRequired for Generic OAuth2; OIDC currently primarily uses ID Token claims; GitHub reads https://api.github.com/user; QQ reads https://graph.qq.com/user/get_user_info; Google / Microsoft currently primarily use ID Token claims
Client ID / Client SecretIdentity-provider application credentials; Secret is redacted when read back
ScopesBlank uses the provider-kind default
Allowed email domainsRestricts accepted domains for auto-linking / auto-provisioning
Claim mappingCustom subject, username, display name, email, email verification status, and related fields

The default scopes are:

text
openid email profile

Generic OAuth2 uses openid email profile when scopes are blank. OIDC also uses openid email profile by default, and the server guarantees that openid is present; if you manually save OIDC scopes as email profile, openid is added back.

Google uses this default when scopes are blank:

text
openid profile email

GitHub uses this default when scopes are blank:

text
read:user user:email

QQ uses this default when scopes are blank:

text
get_user_info

Microsoft uses this default when scopes are blank:

text
openid profile email

Account-Linking Policy

AsterDrive does not treat email as the only identity source. External identities first match existing links by identity_namespace + subject.

PolicyDefaultMeaning
Require verified emailOnThe provider must return a usable email with email_verified=true; otherwise the flow enters email verification or fails
Auto-link by verified emailOffOnly when the provider returns email_verified=true and exactly one local user has the same email
Auto-create local usersOffUnlinked external identities may create normal local users; still constrained by public registration, allowed domains, and email-verification policy

Conservative defaults:

  • For trusted providers such as OIDC / Logto, keep "require verified email" enabled
  • For providers that do not reliably return email_verified=true, do not enable auto-link by verified email
  • The dedicated GitHub provider reads /user/emails and accepts only an email where primary=true and verified=true; when "require verified email" is enabled and no verified primary email is returned, the login is rejected instead of falling back to local email verification
  • The dedicated QQ provider does not return email and has no email_verified semantics; "require verified email" is disabled by default, and first sign-in usually needs email verification or local account binding
  • The dedicated Google provider uses the ID token email_verified claim; when "require verified email" is enabled, false, missing, or non-boolean values reject direct sign-in
  • The dedicated Microsoft provider does not treat email as a verified primary email and does not consume email_verified; "require verified email" is disabled by default, and missing email uses the existing email-verification / account-binding flow

If an external identity cannot log in directly, the user will either log in and link an existing account, or continue through email verification. Email verification depends on the external-login email verification template under Admin -> System Settings -> Mail Delivery.

Claim Mapping

Generic OAuth2 extracts fields from the UserInfo JSON response. Default mappings are:

AsterDrive fieldDefault claimMeaning
Subjectsub, falling back to idRequired; identifies the external identity
EmailemailAccepted only if it is a valid email address
Email verifiedemail_verifiedMissing means false
Display namenameStored as the local display-name snapshot
Usernamepreferred_usernameUsed as the username candidate for auto-created users

Custom claims support three forms:

  • Top-level key: email
  • Dotted path: user.profile.email
  • JSON Pointer: /user/profile/email

Boolean claims may be JSON booleans or strings "true" / "false".

Provider Examples

Logto through Generic OAuth2

For Logto through Generic OAuth2, a typical setup is:

Registration entry points:

Create a Traditional Web application in the Logto Console and add the AsterDrive-generated callback URL to Redirect URI. Other OIDC / OAuth2 providers follow the same pattern from their Applications / Clients page.

text
Provider kind: Generic OAuth2
Authorization URL: http://localhost:3001/oidc/auth
Token URL: http://localhost:3001/oidc/token
UserInfo URL: http://localhost:3001/oidc/me
Scopes: openid email profile
Subject claim: sub
Email claim: email
Email verified claim: email_verified
Display name claim: name
Username claim: preferred_username

In production, replace http://localhost:3001 with the public Logto URL and use HTTPS. If Logto UserInfo returns 403 insufficient_scope and says the access token is missing the openid scope, the authorization request did not include openid; set scopes to openid email profile and start a fresh login.

GitHub

GitHub uses the dedicated github provider. It no longer needs to be configured as Generic OAuth2 with manual endpoints:

Registration entry points:

When creating the OAuth App, add the AsterDrive-generated callback URL to Authorization callback URL.

text
Provider kind: GitHub
Scopes: read:user user:email
Subject claim: fixed from /user.id
Username claim: fixed from /user.login
Display name claim: fixed from /user.name
Email: fixed by filtering /user/emails for primary=true and verified=true

Notes:

  • The admin form does not require GitHub authorization / token / userinfo endpoints
  • GitHub /user.email is not trusted for the login email
  • If GitHub /user/emails does not return a verified primary email, email_verified=false
  • If "require verified email" is enabled, missing a verified primary email rejects the login
QQ Connect

QQ uses the dedicated qq provider. It does not need to be configured as Generic OAuth2 with manual endpoints. QQ Connect website sign-in is not OIDC: there is no discovery, ID token, JWKS, or nonce. AsterDrive follows the QQ OAuth2 flow by exchanging the code for an access token, fetching openid, then reading the user profile.

Create a website application in the QQ Connect management center https://connect.qq.com/manage.html, then copy its App ID and App Key. After saving the AsterDrive provider, register the displayed callback URL as the QQ Connect application callback URL / callback domain. See QQ Connect documentation for OAuth2 setup details.

text
Provider kind: QQ
Client ID: QQ App ID
Client Secret: QQ App Key
Authorization URL: fixed to https://graph.qq.com/oauth2.0/authorize
Token URL: fixed to https://graph.qq.com/oauth2.0/token
OpenID URL: fixed to https://graph.qq.com/oauth2.0/me
UserInfo URL: fixed to https://graph.qq.com/user/get_user_info
Scopes: get_user_info
Subject claim: fixed from openid
Display name claim: fixed from get_user_info.nickname
Email: not returned

Notes:

  • The admin form does not require QQ authorization / token / openid / userinfo endpoints
  • openid is scoped to the QQ App ID; AsterDrive uses qq:{client_id} as the identity namespace to avoid cross-app identity mixing
  • QQ does not return email and does not declare verified email; first sign-in usually enters email verification or local account binding, so do not expect verified-email auto-linking to work
Google

Google uses the dedicated google provider. It no longer needs to be configured as generic OIDC with a manual issuer:

Create an OAuth client ID in Google Cloud Console Credentials https://console.cloud.google.com/apis/credentials, choose Web application as the application type, then add the AsterDrive-generated callback URL to Authorized redirect URIs. You usually also need to configure the OAuth consent screen before first use.

text
Provider kind: Google
Issuer URL: fixed to https://accounts.google.com
Discovery: fixed to https://accounts.google.com/.well-known/openid-configuration
Scopes: openid profile email
Subject claim: fixed from ID token sub
Display name claim: fixed from ID token name
Email claim: fixed from ID token email
Email verified claim: fixed from ID token email_verified
Avatar URL claim: fixed from ID token picture

Notes:

  • The admin form does not require Google issuer / discovery / authorization / token / userinfo endpoints
  • External identities must be linked by sub, not email
  • For later Google Drive access, create a separate OAuth client / authorization flow and do not add drive.* scopes to the login provider
Microsoft Entra ID / Microsoft Account

Microsoft uses the dedicated microsoft provider. It signs users in through OIDC; do not switch it to Generic OAuth2 just because the endpoints contain /oauth2/. OAuth2 access tokens are only needed later when AsterDrive needs to access Microsoft Graph or similar protected resources.

Create the app in Microsoft Entra admin center https://entra.microsoft.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade or Azure portal https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade. Recommended flow:

  1. Choose the Tenant in the AsterDrive Microsoft provider form first.

    • consumers: personal Microsoft Account users only
    • organizations: organization / Entra ID accounts
    • common: both personal Microsoft Account and organization accounts
    • Concrete tenant ID: organization accounts from that tenant only
  2. Open App registrations -> New registration in Microsoft Entra admin center or Azure portal.

  3. Choose the Supported account types that match the AsterDrive Tenant.

    • If AsterDrive Tenant is consumers, choose personal Microsoft accounts only
    • If AsterDrive Tenant is organizations or a concrete tenant ID, choose the matching organizational directory account type
    • If AsterDrive Tenant is common, choose an account type that supports both organizational directory accounts and personal Microsoft accounts
  4. After creating the app, copy Application (client) ID into AsterDrive Client ID.

  5. Open the app's Authentication page, add the Web platform, and paste the callback URL shown by AsterDrive into Redirect URI.

    AsterDrive exchanges the authorization code from the backend, so Microsoft sign-in is a Web / confidential client flow. Do not register the callback URL under Public client/native (mobile and desktop); if it is already there, delete it or do not use that platform entry.

  6. Open Certificates & secrets -> Client secrets and create a client secret.

    AsterDrive must receive the generated Value, not the Secret ID. The Value is shown only once, so create a new secret if it was not saved.

  7. Save the provider in AsterDrive. Use the test button to confirm discovery / JWKS reachability, then run one real Microsoft sign-in from the login page.

Common Microsoft provider setup:

text
Provider kind: Microsoft
Tenant: tenant ID / common / organizations / consumers
Issuer URL: derived automatically, for example https://login.microsoftonline.com/{tenant}/v2.0
Discovery: automatically uses https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration
Scopes: openid profile email
Subject claim: fixed from ID token sub
Display name claim: fixed from ID token name
Email claim: fixed from ID token email
Email verified claim: not used

Tenant may be a concrete tenant ID, organizations, consumers, or common. Multi-tenant entries may return an ID token issuer for the concrete tenant; AsterDrive validates that issuer using Microsoft issuer rules instead of requiring it to literally equal the common / organizations / consumers issuer. Microsoft does not always return an email claim, and its email claim should not be treated like GitHub's verified primary email semantics; if email is missing, use the existing email-verification / account-binding flow. Microsoft Graph permissions are later resource-access authorization and should not be mixed into the login provider's default scopes.

Common pitfalls / reminders

  • AADSTS9002346: Supported account types do not match the AsterDrive tenant. Use the tenant mapping above.
  • AADSTS7000215: the Azure Secret ID was usually entered as the Client Secret. Create a new client secret and paste its generated Value into AsterDrive.
  • AADSTS90023: the Redirect URI is registered under Public client/native (mobile and desktop). Move that Redirect URI to Authentication -> Web, keep the Client Secret in AsterDrive, and start a fresh Microsoft login from the login page instead of refreshing the old callback URL.

Token Request Method

Generic OAuth2 performs only one token exchange to avoid replaying the one-time authorization code.

  • With Client Secret: uses client_secret_post, putting client_id and client_secret in the token endpoint form body
  • Without Client Secret: sends client_id as a public client
  • It does not automatically fall back to client_secret_basic

If a provider only accepts client_secret_basic, wait for explicit client-auth-method configuration; do not rely on retrying the same authorization code.

Troubleshooting

Redirect URI mismatch

First check that Public Site URL is the external URL users actually open. Then copy the redirect URI shown in Admin -> External Authentication to the identity provider. If the public site URL changes, update the provider-side redirect URI too.

OAuth2 userinfo request failed (403 Forbidden; error=insufficient_scope)

Scopes are usually insufficient. Logto / OIDC-style UserInfo usually requires openid. Generic OAuth2 defaults to openid email profile; if this is an old provider or scopes were edited manually, save the scopes again and start a new login.

OAuth2 token exchange failed

Check Client ID, Client Secret, Token URL, and redirect URI. Generic OAuth2 uses client_secret_post when a secret is configured. Providers that only accept client_secret_basic are not directly supported yet.

For Microsoft AADSTS7000215, first check that Client Secret is the Value from Certificates & secrets -> Client secrets, not the Secret ID. If the Value is no longer visible, create a new secret.

For Microsoft AADSTS90023, the Redirect URI is registered under Public client/native (mobile and desktop). Move that Redirect URI to the Authentication -> Web platform, keep the Client Secret in AsterDrive, and start a fresh Microsoft login from the login page instead of reusing or refreshing the old callback URL.

Missing subject

Generic OAuth2 reads sub by default and falls back to id. If the provider uses another field, set Subject claim, for example user.id or /user/id.

Auto-linking requires a usable email, email_verified=true, and exactly one local user with that email. The dedicated GitHub provider only treats email as verified when /user/emails returns a verified primary email; the dedicated Google provider uses ID token email_verified; the dedicated Microsoft provider does not declare email verified, so users may need email verification or password binding.

Admin test passes, real login still fails

The test button only checks provider endpoint configuration and discovery / endpoint reachability. It does not complete a real authorization-code login. Before launch, run real login, auto-create, auto-link, MFA, and email-verification flows with real accounts.

Released under the MIT License