Anchor uses @tijs/atproto-oauth-hono for OAuth authentication with AT Protocol.
import {
createATProtoOAuth,
SQLiteStorage,
} from "jsr:@tijs/atproto-oauth-hono";
const oauth = createATProtoOAuth({
baseUrl: "https://dropanchor.app",
cookieSecret: Deno.env.get("COOKIE_SECRET"),
mobileScheme: "anchor-app://auth-callback",
appName: "Anchor Location Feed",
logoUri:
"https://res.cloudinary.com/dru3aznlk/image/upload/v1754747200/anchor-logo-transparent_nrw70y.png",
policyUri: "https://dropanchor.app/privacy-policy",
sessionTtl: 60 * 60 * 24 * 30, // 30 days for mobile
storage: new SQLiteStorage(rawDb),
logger: console,
});
// Mount OAuth routes
app.route("/", oauth.routes);
| Setting | Value | Purpose |
|---|---|---|
| Base URL | https://dropanchor.app | Production backend URL |
| Mobile Scheme | anchor-app://auth-callback | iOS app custom URL scheme |
| Session TTL | 30 days | Extended for mobile app UX |
COOKIE_SECRET- Session encryption key (32+ characters, cryptographically random)ANCHOR_BASE_URL- Override base URL for development
All authenticated endpoints support cookie-based authentication:
Cookie: sid=<session-token>
Alternative Bearer token authentication (for compatibility):
Authorization: Bearer <session-token>
Recommended: Use cookie-based authentication. After OAuth, create an HTTPCookie and add it to HTTPCookieStorage (iOS) or document.cookie (web).
For complete OAuth flow details, mobile integration, security considerations, and implementation examples:
📱 Mobile OAuth Guide (Package documentation)
This guide includes:
- Complete OAuth flow with sequence diagrams
- All API endpoints with request/response schemas
- PKCE implementation details
- Session token format and cookie setup
- Error handling and recovery strategies
- iOS Swift and Android Kotlin examples
- Security best practices
After authentication, use the session cookie to call authenticated endpoints:
curl -X POST "https://dropanchor.app/api/checkins" \ -b "sid=YOUR_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{"place": {...}, "message": "Great spot!"}'
curl -X DELETE "https://dropanchor.app/api/checkins/did:plc:abc/3k2abc" \ -b "sid=YOUR_SESSION_TOKEN"
See API Documentation for complete endpoint reference.
The Anchor iOS app uses ASWebAuthenticationSession for OAuth:
- Load OAuth page:
/mobile-auth - Complete OAuth: Receive
anchor-app://auth-callback?session_token=... - Store token: Save to iOS Keychain
- Create cookie: Add to HTTPCookieStorage for URLSession
- Make requests: All API calls automatically include cookie
See the Mobile OAuth Guide for implementation details.
- Duration: 30 days
- Refresh: Automatic via backend
- Expiration: User must re-authenticate
const session = await oauth.validateSession(request);
if (!session.valid) {
// User needs to re-authenticate
}
For local development, override the base URL:
export ANCHOR_BASE_URL=http://localhost:8000
- Start the backend:
deno task dev - Visit
/mobile-authin browser - Enter test handle:
test.bsky.social - Complete OAuth flow
- Clear cookies and re-authenticate
- Check
COOKIE_SECRETis set correctly - Verify session hasn't exceeded 30-day TTL
- Verify
mobileSchemematches iOS app URL scheme - Check callback URL format:
anchor-app://auth-callback - Ensure session_token is being stored in Keychain
- Backend handles refresh automatically
- No manual refresh needed for cookie-based auth
- If refresh fails, user must re-authenticate
- Session tokens are sealed with Iron Session encryption
- Cookies use HttpOnly, Secure, and SameSite=Lax flags
- PKCE protects against authorization code interception
- DPoP tokens managed entirely on backend
- No token exposure in mobile app (only sealed session token)
See Security Considerations in the Mobile OAuth Guide.