External Authentication
External authentication maps an external identity provider login result to an AsterDrive local user. The admin entry point is:
Admin -> External AuthenticationAsterDrive currently supports six provider kinds:
| Kind | Best for | Behavior |
|---|---|---|
oidc / OpenID Connect | Standard OIDC identity providers | Uses issuer discovery, authorization-code flow, PKCE, nonce, and ID Token validation |
generic_oauth2 / Generic OAuth2 | Providers that expose OAuth2 authorization-code + UserInfo but need manual endpoints | Manually configures authorization / token / userinfo endpoints, uses authorization-code flow with PKCE, and extracts identity from UserInfo |
github / GitHub | GitHub OAuth App sign-in | Uses fixed GitHub OAuth endpoints, reads identity fields from /user, and calls /user/emails to accept only the verified primary email |
qq / QQ | QQ Connect website sign-in | Uses fixed QQ OAuth2 endpoints, reads openid first, then calls get_user_info for profile data and links external identities by openid |
google / Google | Google OIDC sign-in | Uses fixed Google Accounts issuer / discovery, validates the ID token, and links external identities by sub |
microsoft / Microsoft | Microsoft Entra ID / Microsoft Account OIDC sign-in | Derives 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:
Admin -> System Settings -> Site Configuration -> Public Site URLis the real external URL- The reverse proxy already handles HTTPS, Host, real client IPs, and large request bodies
- An application has been created on the identity provider side, with a Client ID ready
- 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:
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.
| Provider | Where to create it | Redirect URI field |
|---|---|---|
| OIDC / Generic OAuth2 | Your identity provider admin console, such as the Applications / Clients page in Logto, Authentik, Keycloak, or Zitadel | The 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 |
| GitHub | GitHub user or organization Settings -> Developer settings -> OAuth Apps -> New OAuth App | OAuth App Authorization callback URL |
| QQ Connect management center https://connect.qq.com/manage.html website application | Application callback URL / callback domain; use the callback URL shown after saving the AsterDrive provider | |
Google Cloud Console APIs & Services -> Credentials -> Create Credentials -> OAuth client ID | OAuth client Authorized redirect URIs | |
| Microsoft | Microsoft Entra admin center / Azure portal App registrations -> New registration | Add 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
| Field | Meaning |
|---|---|
| Display name | Name shown on the login button |
| Icon URL | May 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 URL | Required 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 URL | Required for Generic OAuth2; discovered for OIDC; fixed for GitHub / QQ; discovered from Google / Microsoft fixed discovery |
| Token URL | Required for Generic OAuth2; discovered for OIDC; fixed for GitHub / QQ; discovered from Google / Microsoft fixed discovery |
| UserInfo URL | Required 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 Secret | Identity-provider application credentials; Secret is redacted when read back |
| Scopes | Blank uses the provider-kind default |
| Allowed email domains | Restricts accepted domains for auto-linking / auto-provisioning |
| Claim mapping | Custom subject, username, display name, email, email verification status, and related fields |
The default scopes are:
openid email profileGeneric 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:
openid profile emailGitHub uses this default when scopes are blank:
read:user user:emailQQ uses this default when scopes are blank:
get_user_infoMicrosoft uses this default when scopes are blank:
openid profile emailAccount-Linking Policy
AsterDrive does not treat email as the only identity source. External identities first match existing links by identity_namespace + subject.
| Policy | Default | Meaning |
|---|---|---|
| Require verified email | On | The provider must return a usable email with email_verified=true; otherwise the flow enters email verification or fails |
| Auto-link by verified email | Off | Only when the provider returns email_verified=true and exactly one local user has the same email |
| Auto-create local users | Off | Unlinked 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/emailsand accepts only an email whereprimary=trueandverified=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_verifiedsemantics; "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_verifiedclaim; when "require verified email" is enabled,false, missing, or non-boolean values reject direct sign-in - The dedicated Microsoft provider does not treat
emailas a verified primary email and does not consumeemail_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 field | Default claim | Meaning |
|---|---|---|
| Subject | sub, falling back to id | Required; identifies the external identity |
email | Accepted only if it is a valid email address | |
| Email verified | email_verified | Missing means false |
| Display name | name | Stored as the local display-name snapshot |
| Username | preferred_username | Used 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:
- Logto Cloud Console: https://cloud.logto.io/
- Self-hosted Logto Console:
https://<logto-host>/console - Logto applications documentation: https://docs.logto.io/end-user-flows/sign-in-experience/applications
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.
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_usernameIn 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:
- Personal account OAuth Apps: https://github.com/settings/developers
- Organization OAuth Apps:
https://github.com/organizations/{org}/settings/applications - GitHub official guide: https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app
When creating the OAuth App, add the AsterDrive-generated callback URL to Authorization callback URL.
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=trueNotes:
- The admin form does not require GitHub authorization / token / userinfo endpoints
- GitHub
/user.emailis not trusted for the login email - If GitHub
/user/emailsdoes 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.
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 returnedNotes:
- The admin form does not require QQ authorization / token / openid / userinfo endpoints
openidis scoped to the QQ App ID; AsterDrive usesqq:{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 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.
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 pictureNotes:
- 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:
Choose the Tenant in the AsterDrive Microsoft provider form first.
consumers: personal Microsoft Account users onlyorganizations: organization / Entra ID accountscommon: both personal Microsoft Account and organization accounts- Concrete tenant ID: organization accounts from that tenant only
Open
App registrations -> New registrationin Microsoft Entra admin center or Azure portal.Choose the Supported account types that match the AsterDrive Tenant.
- If AsterDrive Tenant is
consumers, choose personal Microsoft accounts only - If AsterDrive Tenant is
organizationsor 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
- If AsterDrive Tenant is
After creating the app, copy
Application (client) IDinto AsterDrive Client ID.Open the app's
Authenticationpage, add theWebplatform, 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.Open
Certificates & secrets -> Client secretsand create a client secret.AsterDrive must receive the generated
Value, not theSecret ID. TheValueis shown only once, so create a new secret if it was not saved.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:
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 usedTenant 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 AzureSecret IDwas usually entered as the Client Secret. Create a new client secret and paste its generatedValueinto AsterDrive.AADSTS90023: the Redirect URI is registered underPublic client/native (mobile and desktop). Move that Redirect URI toAuthentication -> 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, puttingclient_idandclient_secretin the token endpoint form body - Without Client Secret: sends
client_idas 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.
Email does not auto-link
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.