9.4 KiB
9.4 KiB
IAM Service Authentication Guide
Complete guide for authentication using GoodGo IAM Service with OAuth2/OpenID Connect.
Overview
The IAM Service provides OAuth2/OIDC authentication using Duende IdentityServer:
- Password Grant - User login with email/password
- Refresh Token - Token renewal without re-authentication
- Client Credentials - Service-to-service authentication
- Email Verification - SMTP-based email confirmation
- Two-Factor Authentication (2FA) - TOTP with QR code and recovery codes
- Social Login - Google and Facebook OAuth integration
Quick Start
1. Register a User
curl -X POST http://localhost:5001/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "Password123!",
"firstName": "John",
"lastName": "Doe"
}'
2. Login (Get Tokens)
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "username=user@example.com" \
-d "password=Password123!" \
-d "scope=openid profile email offline_access"
Response:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "eyJhbGciOiJSUzI1NiIs...",
"scope": "openid profile email offline_access"
}
3. Use Access Token
curl http://localhost:5001/api/v1/users/me \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIs..."
OAuth2 Grant Types
Password Grant (User Login)
For trusted first-party applications where users enter credentials directly.
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=password" \
-d "username=user@example.com" \
-d "password=Password123!" \
-d "scope=openid profile email offline_access"
| Parameter | Required | Description |
|---|---|---|
grant_type |
Yes | Must be password |
username |
Yes | User's email |
password |
Yes | User's password |
scope |
No | Space-separated scopes |
Refresh Token
Renew access token without re-entering credentials.
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=eyJhbGciOiJSUzI1NiIs..."
| Parameter | Required | Description |
|---|---|---|
grant_type |
Yes | Must be refresh_token |
refresh_token |
Yes | Valid refresh token |
Client Credentials (Service-to-Service)
For backend services authenticating without user context.
curl -X POST http://localhost:5001/connect/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=goodgo-service" \
-d "client_secret=service-secret" \
-d "scope=api"
| Parameter | Required | Description |
|---|---|---|
grant_type |
Yes | Must be client_credentials |
client_id |
Yes | Registered client ID |
client_secret |
Yes | Client secret |
scope |
No | Requested scopes |
Note: Client applications must be registered in the database before use.
Token Lifetimes
| Token Type | Lifetime | Use |
|---|---|---|
| Access Token | 15 minutes | API authorization |
| Refresh Token | 7 days | Token renewal |
Available Scopes
| Scope | Description |
|---|---|
openid |
Required for OIDC |
profile |
User profile (name) |
email |
User email |
roles |
User roles |
offline_access |
Get refresh token |
api |
API access |
API Endpoints
Authentication
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/auth/register |
Register new user |
POST |
/connect/token |
OAuth2 token endpoint |
POST |
/api/v1/auth/change-password |
Change password (auth required) |
POST |
/api/v1/auth/logout |
Revoke tokens (auth required) |
Email Verification
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/auth/send-verification-email |
Send email verification link (auth required) |
POST |
/api/v1/auth/confirm-email |
Confirm email with token |
Two-Factor Authentication (2FA)
| Method | Endpoint | Description |
|---|---|---|
POST |
/api/v1/auth/2fa/enable |
Enable 2FA (get QR code) (auth required) |
POST |
/api/v1/auth/2fa/verify |
Verify TOTP code & activate (auth required) |
POST |
/api/v1/auth/2fa/disable |
Disable 2FA (auth required) |
Social Login
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/auth/external-login/{provider} |
Initiate OAuth flow (Google/Facebook) |
GET |
/api/v1/auth/external-callback |
Handle OAuth callback |
GET |
/api/v1/auth/linked-accounts |
Get linked OAuth providers (auth required) |
User Management
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/v1/users |
List users (paginated) |
GET |
/api/v1/users/me |
Current user info |
GET |
/api/v1/users/{id} |
Get user by ID |
PUT |
/api/v1/users/{id} |
Update user |
DELETE |
/api/v1/users/{id} |
Delete user (soft) |
Integration Examples
JavaScript/TypeScript
// Login
const response = await fetch('http://localhost:5001/connect/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'password',
username: 'user@example.com',
password: 'Password123!',
scope: 'openid profile email offline_access'
})
});
const { access_token, refresh_token } = await response.json();
// Use token
const user = await fetch('http://localhost:5001/api/v1/users/me', {
headers: { 'Authorization': `Bearer ${access_token}` }
}).then(r => r.json());
C# / .NET
// Login
var client = new HttpClient();
var content = new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "password",
["username"] = "user@example.com",
["password"] = "Password123!",
["scope"] = "openid profile email offline_access"
});
var response = await client.PostAsync("http://localhost:5001/connect/token", content);
var tokens = await response.Content.ReadFromJsonAsync<TokenResponse>();
// Use token
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", tokens.AccessToken);
var user = await client.GetFromJsonAsync<UserDto>("/api/v1/users/me");
Email Verification
Send Verification Email
curl -X POST http://localhost:5001/api/v1/auth/send-verification-email \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"email": "user@example.com"}'
Confirm Email
curl -X POST http://localhost:5001/api/v1/auth/confirm-email \
-H "Content-Type: application/json" \
-d '{"userId": "user-guid", "token": "confirmation-token"}'
Two-Factor Authentication (2FA)
Enable 2FA
curl -X POST http://localhost:5001/api/v1/auth/2fa/enable \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response:
{
"success": true,
"data": {
"secretKey": "JBSWY3DPEHPK3PXP",
"qrCodeBase64": "data:image/png;base64,...",
"recoveryCodes": ["code1", "code2", "code3"]
}
}
Verify 2FA Code
curl -X POST http://localhost:5001/api/v1/auth/2fa/verify \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
Disable 2FA
curl -X POST http://localhost:5001/api/v1/auth/2fa/disable \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'
Social Login
Initiate OAuth Flow
Redirect user to:
GET http://localhost:5001/api/v1/auth/external-login/Google?returnUrl=http://your-app/callback
GET http://localhost:5001/api/v1/auth/external-login/Facebook?returnUrl=http://your-app/callback
Get Linked Accounts
curl http://localhost:5001/api/v1/auth/linked-accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Response:
{
"success": true,
"data": {
"linkedProviders": [
{"provider": "Google", "providerDisplayName": "Google"},
{"provider": "Facebook", "providerDisplayName": "Facebook"}
]
}
}
Error Responses
Common Errors
| Error | HTTP Code | Description |
|---|---|---|
invalid_grant |
400 | Invalid credentials |
invalid_client |
400 | Unknown client_id |
invalid_scope |
400 | Invalid scope requested |
unauthorized |
401 | Invalid/expired token |
Error Response Format
{
"error": "invalid_grant",
"error_description": "The username or password is incorrect."
}
Security Best Practices
- Store tokens securely - Use httpOnly cookies or secure storage
- Refresh tokens proactively - Before access token expires
- Use HTTPS in production - Never send credentials over HTTP
- Logout properly - Call logout endpoint to revoke tokens
- Validate tokens server-side - Don't trust client-side validation
Swagger UI
Access interactive API documentation: