OpenID Connect (OIDC)
TIC Identity stöder OpenID Connect för standardiserad integration med BankID. Använd vanliga OIDC-bibliotek för att integrera autentisering och få tillgång till svenska berikningsdata via UserInfo-endpointen.
Översikt
TIC Identity:s OIDC-implementation inkluderar:
- Authorization Code Flow med PKCE - Säker autentisering för webbappar och native-appar
- Discovery Document - Automatisk konfiguration via
.well-known/openid-configuration - Svenska berikningsscopes - Hämta folkbokföring, bolagsengagemang, fastigheter och mer
- BankID riskbedömning - Automatisk inkludering av riskindikator
- Dubbelt dataformat - Både förenklade OIDC-claims och rådata från svenska myndigheter
Kom igång
1. Aktivera OIDC
OIDC aktiveras i portalen under fliken "OIDC" i inställningarna. När OIDC är aktiverat får du tillgång till discovery-URL:en.
2. Skapa en OIDC-klient
Varje applikation som ska använda OIDC behöver en egen klient med:
- Client ID - Offentlig identifierare
- Client Secret - Hemlig nyckel (visas endast vid skapande)
- Redirect URIs - Godkända callback-URL:er
- Post-logout Redirect URIs - Godkända URL:er för omdirigering efter utloggning (valfritt)
- Tillåtna scopes - Vilken data klienten får begära
3. Konfigurera ditt OIDC-bibliotek
Använd discovery-URL:en för automatisk konfiguration:
https://id.tic.io/{tenant-slug}/.well-known/openid-configuration
Endpoints
| Endpoint | URL | Beskrivning |
|---|---|---|
| Discovery | /.well-known/openid-configuration |
OIDC-konfiguration och metadata |
| Authorization | /oidc/authorize |
Starta autentisering |
| Token | /oidc/token |
Byt authorization code mot tokens |
| UserInfo | /oidc/userinfo |
Hämta användardata och berikningar |
| JWKS | /oidc/jwks |
Publika nycklar för tokenvalidering |
| End Session | /connect/endsession |
RP-initierad utloggning |
| Revocation | /connect/revoke |
Återkalla tokens |
Scopes och Claims
Scopes bestämmer vilken data som inkluderas i tokens och UserInfo-svaret. Berikningsscopes kräver att enrichment är aktiverat för din tenant.
Standardscopes
| Scope | Claims | Beskrivning |
|---|---|---|
openid |
sub |
Obligatoriskt. Subject identifier (hashad personnummer) |
profile |
name, given_name, family_name, birthdate, locale |
Grundläggande profilinformation från BankID |
nin |
nin, nin_type, nin_issuing_country |
Svenskt personnummer |
offline_access |
- | Får refresh token för förnyelse av access token |
BankID-specifika scopes
| Scope | Claims | Beskrivning |
|---|---|---|
bankid_device |
bankid_device_ip |
IP-adress där BankID-autentisering skedde (för bedrägeridetektion) |
risk.thirdPartyEvaluation) inkluderas automatiskt i UserInfo när tillgängligt.
Möjliga värden: low, moderate, high.
Berikningsscopes
Dessa scopes triggar datahämtning från svenska myndigheter och register. Data returneras både i förenklat OIDC-format och som rådata.
| Scope | Källa | Claims (förenklad + rådata) |
|---|---|---|
address |
SPAR | address + spar |
company_roles |
Bolagsverket | company_roles + company_roles_raw |
real_estate |
Lantmäteriet | real_estate + real_estate_raw |
income |
Skatteverket | income + income_raw |
ip_intelligence |
IP-Intelligence | ip_intelligence + ip_intelligence_raw |
Bolagsverket positionTypes-koder
Fältet positionTypes i company_roles_raw innehåller en eller flera rollkoder
från Bolagsverkets klassificering. En person kan ha flera koder samtidigt (t.ex. ["VD", "LE"]).
"BOLAGSENGAGEMANG" som generisk platshållarkod.
I produktion returneras de specifika koderna nedan.
| Kod | Beskrivning |
|---|---|
VD | Verkställande direktör |
VVD | Vice verkställande direktör |
EVD | Extern verkställande direktör (ej styrelsemedlem) |
EVVD | Extern vice verkställande direktör (ej styrelsemedlem) |
SVD | Ställföreträdande verkställande direktör |
OF | Ordförande |
VOF | Vice ordförande |
LE | Styrelseledamot |
SU | Styrelsesuppleant |
VLE | Verkställande ledamot |
EFT | Extern firmatecknare (ej styrelsemedlem) |
BO | Bolagsman |
KP | Komplementär |
KD | Kommanditdelägare |
IN | Innehavare |
FÖ | Föreståndare |
PO | Prokurist |
REP | Representant |
LI | Likvidator |
LS | Likvidatorssuppleant |
DELG | Delgivningsbar person (särskild delgivningsmottagare) |
AK | Aktuarie |
REV | Revisor |
REVH | Huvudansvarig revisor |
REVS | Revisorssuppleant |
REVL | Lekmannarevisor |
REVSL | Lekmannarevisorssuppleant |
REVT | Revisor med tillstånd |
REVST | Aktuarie revisorssuppleant |
HREV | Revisor hållbarhetsrapport |
HREVH | Huvudansvarig revisor hållbarhetsrapport |
HREVS | Revisorssuppleant hållbarhetsrapport |
Firmateckningsrätt
Fältet signatureDescription i company_roles_raw innehåller den registrerade
firmateckningsregeln från Bolagsverket, t.ex. "Firman tecknas av styrelsen. Firman tecknas två i förening."
Rekommendation: Använd signatureDescription som primär källa för att
bedöma firmateckningsrätt. Firmateckningsregler varierar mellan bolag och kan inte härledas enbart
från positionTypes. Använd positionTypes för att identifiera personens
roll i bolaget, och signatureDescription för att avgöra om rollen ger firmateckningsrätt.
AI-analys av firmateckningsrätt
Fältet signingAuthorityAnalysis i company_roles_raw innehåller en
AI-genererad analys av firmateckningsregeln. Analysen tolkar signatureDescription
och matchar reglerna mot de registrerade styrelsemedlemmarna och funktionärerna.
signingAuthorityAnalysis genereras av AI och kan innehålla felaktigheter.
Verifiera alltid resultatet mot den ursprungliga signatureDescription innan
du fattar beslut baserat på analysen. Använd analysen som ett stöd, inte som en auktoritativ källa.
| Fält | Typ | Beskrivning |
|---|---|---|
summary |
string |
Sammanfattning på svenska av firmateckningsreglerna |
rules |
array |
Tolkade firmateckningsregler med typ (alone, joint, board, other) och antal signatärer som krävs |
eligiblePersons |
array |
Personer som matchar firmateckningsreglerna, med personId, personalIdentityNumber, roller och vilka regler som gäller |
eligiblePersons[].canSignAlone |
boolean |
Om personen kan teckna firman ensam |
Authorization Code Flow
Steg 1: Redirecta till Authorization
GET /oidc/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://your-app.com/callback
&scope=openid profile nin address company_roles
&state=random_state_value
&nonce=random_nonce_value
&code_challenge=BASE64URL(SHA256(code_verifier))
&code_challenge_method=S256
Steg 2: Användaren autentiserar med BankID
Användaren visas en BankID-autentiseringssida och genomför autentisering i BankID-appen. Efter lyckad autentisering redirectas de tillbaka.
Steg 3: Hantera callback
GET https://your-app.com/callback?
code=AUTHORIZATION_CODE
&state=random_state_value
Steg 4: Byt code mot tokens
curl -X POST https://id.tic.io/{tenant}/oidc/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=AUTHORIZATION_CODE" \
-d "redirect_uri=https://your-app.com/callback" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "code_verifier=YOUR_CODE_VERIFIER"
Svar:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 3600,
"id_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g...",
"scope": "openid profile nin address company_roles"
}
Steg 5: Hämta UserInfo
curl https://id.tic.io/{tenant}/oidc/userinfo \
-H "Authorization: Bearer ACCESS_TOKEN"
UserInfo-svar
UserInfo-svaret innehåller data baserat på begärda scopes. Berikningsdata returneras i två format: förenklat OIDC-format och fullständig rådata.
session_id som kan användas med det
konventionella beriknings-API:et om du föredrar det formatet.
{
"sub": "a1b2c3d4e5f6789012345678901234567",
// Session ID for conventional API access
"session_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
// profile scope
"name": "Anna Andersson",
"given_name": "Anna",
"family_name": "Andersson",
"birthdate": "1985-03-15",
"locale": "sv-SE",
"updated_at": 1706789012,
// nin scope
"nin": "198503151234",
"nin_type": "PERSON",
"nin_issuing_country": "SE",
// bankid_device scope
"bankid_device_ip": "192.168.1.100",
// BankID risk (alltid inkluderat om tillgängligt)
"risk": {
"thirdPartyEvaluation": {
"riskValue": "low",
"source": "bankid"
}
},
// address scope - förenklad
"address": {
"street_address": "Storgatan 1",
"locality": "Stockholm",
"postal_code": "11122",
"country": "Sweden",
"formatted": "Storgatan 1\n11122 Stockholm\nSweden"
},
// address scope - rådata från SPAR
"spar": {
"Person_IdNummer": "198503151234",
"Namn_Fornamn": "Anna Maria",
"Namn_Efternamn": "Andersson",
"Folkbokforingsadress_SvenskAdress_Utdelningsadress1": "Storgatan 1",
"Folkbokforingsadress_SvenskAdress_PostNr": "11122",
"Folkbokforingsadress_SvenskAdress_Postort": "STOCKHOLM"
// ... fler fält
},
// company_roles scope - förenklad
"company_roles": [
{
"org_number": "5591234567",
"company_name": "Exempel AB",
"role": "Styrelseledamot",
"role_code": "LE",
"start_date": "2020-01-15"
}
],
// company_roles scope - rådata
"company_roles_raw": [
{
"companyId": 12345,
"companyRegistrationNumber": "5591234567",
"legalName": "Exempel AB",
"legalEntityType": "AB",
"positionTypes": ["VD", "LE"],
"positionDescriptions": ["Verkställande direktör", "Styrelseledamot"],
"positionStart": "2020-01-15T00:00:00Z",
"positionEnd": null,
"companyStatus": "Active",
"signatureDescription": "Firman tecknas av styrelsen. Firman tecknas två i förening.",
"signingAuthorityAnalysis": {
"summary": "Firman tecknas av styrelsen gemensamt, eller av två styrelseledamöter i förening.",
"rules": [
{
"description": "Styrelsen gemensamt",
"type": "board",
"requiredSignatories": null,
"requiredRoles": ["LE", "OF"]
},
{
"description": "Två i förening",
"type": "joint",
"requiredSignatories": 2,
"requiredRoles": ["LE", "OF", "VD"]
}
],
"eligiblePersons": [
{
"personId": 42,
"personalIdentityNumber": "198001011234",
"name": "Anna Svensson",
"roles": ["Verkställande direktör", "Styrelseledamot"],
"canSignAlone": false,
"applicableRules": ["Två i förening"]
}
]
}
}
],
// real_estate scope - förenklad
"real_estate": [
{
"property_designation": "STOCKHOLM VASASTAN 1:23",
"municipality": "STOCKHOLM",
"ownership_share": "1/2",
"acquisition_date": "2018-06-01"
}
],
// real_estate scope - rådata
"real_estate_raw": [
{
"FastighetObjektIdentitet": "abc123",
"Registerbeteckning": "STOCKHOLM VASASTAN 1:23",
"AndelTaljare": 1,
"AndelNamnare": 2,
"OwnershipStartDate": "2018-06-01T00:00:00Z"
}
],
// income scope - förenklad (senaste år)
"income": {
"year": 2023,
"employment_income": 450000,
"capital_income": 25000,
"business_income": 0,
"total_income": 475000
},
// income scope - rådata (alla år)
"income_raw": [
{
"AR_DEKL": 2023,
"INK_TJ": 450000,
"OSKOTT_KAP": 25000
// ... fler fält
}
],
// ip_intelligence scope - förenklad
"ip_intelligence": {
"ip_address": "85.123.45.67",
"country": "Sweden",
"city": "Stockholm",
"is_vpn": false,
"is_proxy": false,
"is_tor": false,
"risk_score": 0.05
},
// ip_intelligence scope - rådata
"ip_intelligence_raw": {
"InitiatingIp": {
"IpAddress": "85.123.45.67",
"CountryCode": "SE",
"CountryName": "Sweden",
"ConfidenceScore": 0,
"IsLikelyVpn": false,
"IsTor": false
},
"OverallRisk": {
"Level": "Low",
"Score": 5
}
}
}
Exempelintegrationer
ASP.NET Core
// Program.cs
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = "https://id.tic.io/your-tenant";
options.ClientId = "your-client-id";
options.ClientSecret = "your-client-secret";
options.ResponseType = "code";
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
// Lägg till önskade scopes
options.Scope.Add("profile");
options.Scope.Add("nin");
options.Scope.Add("address");
options.Scope.Add("company_roles");
});
Next.js (NextAuth.js)
// pages/api/auth/[...nextauth].js
import NextAuth from "next-auth";
export default NextAuth({
providers: [
{
id: "tic-identity",
name: "TIC Identity",
type: "oauth",
wellKnown: "https://id.tic.io/your-tenant/.well-known/openid-configuration",
clientId: process.env.TIC_CLIENT_ID,
clientSecret: process.env.TIC_CLIENT_SECRET,
authorization: {
params: {
scope: "openid profile nin address company_roles"
}
},
idToken: true,
profile(profile) {
return {
id: profile.sub,
name: profile.name,
personalNumber: profile.nin,
};
},
},
],
});
Python (Authlib)
from authlib.integrations.flask_client import OAuth
oauth = OAuth(app)
oauth.register(
name='tic_identity',
client_id='your-client-id',
client_secret='your-client-secret',
server_metadata_url='https://id.tic.io/your-tenant/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid profile nin address company_roles'
}
)
@app.route('/login')
def login():
redirect_uri = url_for('callback', _external=True)
return oauth.tic_identity.authorize_redirect(redirect_uri)
@app.route('/callback')
def callback():
token = oauth.tic_identity.authorize_access_token()
userinfo = oauth.tic_identity.userinfo()
# userinfo innehåller nu all begärd data
return f"Välkommen {userinfo['name']}"
Token-livstider
Standardlivstider kan justeras i portalen:
| Token | Standard | Intervall |
|---|---|---|
| Access Token | 1 timme | 5 min - 24 timmar |
| ID Token | 1 timme | 5 min - 24 timmar |
| Refresh Token | 30 dagar | 1 timme - 1 år |
| Authorization Code | 5 minuter | Fast |
Utloggning (RP-Initiated Logout)
För att logga ut en användare, redirecta till End Session-endpointen med ID-token som hint.
Om en registrerad post_logout_redirect_uri anges redirectas användaren dit efter utloggning.
GET /connect/endsession?
id_token_hint=eyJhbGciOiJSUzI1NiIs...
&post_logout_redirect_uri=https://your-app.com/logged-out
&state=optional_state_value
| Parameter | Obligatorisk | Beskrivning |
|---|---|---|
id_token_hint |
Ja* | ID-token som erhölls vid inloggning. Krävs om post_logout_redirect_uri anges. |
post_logout_redirect_uri |
Nej | URL dit användaren redirectas efter utloggning. Måste vara registrerad på klienten. |
state |
Nej | Godtyckligt värde som skickas tillbaka som query-parameter vid redirect. |
Om ingen post_logout_redirect_uri anges visas en bekräftelsesida.
Post-logout redirect URIs konfigureras per klient i portalen.
Säkerhet
PKCE (Proof Key for Code Exchange)
PKCE är obligatoriskt för alla klienter och skyddar mot authorization code interception-attacker.
Använd code_challenge_method=S256 för maximal säkerhet.
Tokenvalidering
Validera alltid ID-tokens och access tokens i din backend:
- Verifiera signaturen mot JWKS-endpointen
- Kontrollera
iss(issuer) ochaud(audience) - Verifiera att
exp(expiration) inte har passerat - Kontrollera
nonceom du använde det i authorization-request
Felhantering
OIDC-fel returneras enligt OAuth 2.0-specifikationen:
| Felkod | Beskrivning |
|---|---|
invalid_request |
Ogiltig eller saknad parameter |
unauthorized_client |
Klienten får inte använda denna grant type |
access_denied |
Användaren avbröt eller nekade åtkomst |
invalid_scope |
Begärt scope är ogiltigt eller inte tillåtet |
invalid_grant |
Authorization code är ogiltig eller har redan använts |
invalid_client |
Client ID eller secret är felaktig |
Nästa steg
- Läs mer om berikningsdata
- BankID-specifika inställningar
- Konfigurera webhooks för realtidsnotifikationer
- Gå till portalen för att aktivera OIDC